TW
Tripwire
Find contracts. Test them. Review real vulns.

Analysis Run

019d5666-71ff-7060-88f6-c0d2b403a889

complete
Chain ID
1
Address
Block Number
Created
Sat, Apr 4, 2026 2:50 AM
Review Summary

What survived the funnel

Open this run to answer one question: is this real attacker-relevant behavior with real impact, or just normal contract plumbing?

Confirmed
0
Validated
0
Source
Verified
Review Backing
Present
Best current signal
Permissionless initializers let the first caller seize control and mint supply
crit 0 high 0 direct contract
Review Checklist
1. Read the findings table first. Ignore raw jobs until the result looks real.
2. Confirm attacker control, not just the existence of a sink.
3. Confirm money or privilege impact.
4. Keep it if the behavior is real. Kill it if this is normal proxy, admin, or upgrade plumbing.

Processing Jobs

Status & attempts
ID Type Status Attempts Heartbeat
42834 artifact.fetch complete 1 / 3 1 week ago
42835 proxy.resolve complete 1 / 3 1 week ago
42836 tool.cast_disasm complete 1 / 3 1 week ago
42837 analysis.bundle complete 1 / 3 1 week ago
42838 capability.graph complete 1 / 3 1 week ago
42839 detector.run complete 1 / 3 1 week ago
42840 validation.fork complete 1 / 3 1 week ago
42949 report.consolidate complete 1 / 6 1 week ago

Artifact

Runtime bytecode: available
Creation TX:
Deployer:
Proxy: no not_proxy
Implementation:
Verified Source: yes
Proxy evidence
{
    "status": "not_proxy"
}

Slither

tool.slither

No slither job recorded yet.

Codex

report.consolidate
Job Status
complete
Attempts
1 / 6
Findings
3
No findings?
no
Summary
Found 3 issues: multiple constructor-deployed contracts can be hijacked through permissionless initializers, mailbox-authenticated hooks can be triggered directly by anyone for the current latest message, and recipient-specific routing quotes do not match execution.
View stdout
{"no_findings":false,"summary":"Found 3 issues: multiple constructor-deployed contracts can be hijacked through permissionless initializers, mailbox-authenticated hooks can be triggered directly by anyone for the current latest message, and recipient-specific routing quotes do not match execution.","findings":[{"severity":"high","category":"auth","title":"Permissionless initializers let the first caller seize control and mint supply","exploit_scenario":"Several production contracts are deployed with constructors but defer critical setup to unrestricted `initializer` functions. If deployment and initialization are not atomic, an attacker can front-run the intended initializer call, become owner, install malicious hooks/ISMs/bridge endpoints, or mint the full initial token/NFT supply to themselves. For example, hijacking `Mailbox.initialize` gives the attacker control over `defaultIsm/defaultHook/requiredHook`, while hijacking `HypERC20.initialize` or `HypERC721.initialize` mints the initial supply to the attacker.","recommendation":"Do not expose public initialization for constructor-deployed instances. Move critical setup into the constructor or gate initialization to the constructor-established owner with a separate one-time guard. If these are meant to be proxy implementations, disable initializers on the implementation and initialize atomically via proxy constructor calldata.","evidence":"`initialize`/`setAuthorizedHook` are externally callable with only the OZ `initializer` modifier, which enforces one-time execution but does not authenticate the caller. Some of these initializers also mint to `msg.sender` or rewrite owner/configuration.","locations":["AUDIT_BUNDLE.txt:9360 (contracts/isms/hook/AbstractMessageIdAuthorizedIsm.sol)","AUDIT_BUNDLE.txt:10150 (contracts/hooks/igp/InterchainGasPaymaster.sol)","AUDIT_BUNDLE.txt:12612 (contracts/isms/routing/DomainRoutingIsm.sol)","AUDIT_BUNDLE.txt:12623 (contracts/isms/routing/DomainRoutingIsm.sol)","AUDIT_BUNDLE.txt:13188 (contracts/Mailbox.sol)","AUDIT_BUNDLE.txt:13664 (contracts/middleware/InterchainAccountRouter.sol)","AUDIT_BUNDLE.txt:14255 (contracts/middleware/InterchainQueryRouter.sol)","AUDIT_BUNDLE.txt:14545 (contracts/middleware/liquidity-layer/adapters/CircleBridgeAdapter.sol)","AUDIT_BUNDLE.txt:14862 (contracts/middleware/liquidity-layer/adapters/PortalAdapter.sol)","AUDIT_BUNDLE.txt:15074 (contracts/middleware/liquidity-layer/LiquidityLayerRouter.sol)","AUDIT_BUNDLE.txt:16441 (contracts/token/HypERC20.sol)","AUDIT_BUNDLE.txt:16992 (contracts/token/HypERC721.sol)"]},{"severity":"high","category":"auth","title":"Anyone can call post-dispatch hooks directly for the current latest message","exploit_scenario":"After any legitimate dispatch, the full message bytes are public in the `Dispatch` event and `latestDispatchedId` stays set until the next dispatch. Because `AbstractPostDispatchHook.postDispatch` is permissionless, an attacker can call `MerkleTreeHook.postDispatch` directly and insert the same message ID into the Merkle tree again, corrupting checkpoint state. The same pattern also lets an attacker directly trigger message-id authorization hooks (`ERC5164Hook`/`OPStackHook`) for the current latest message, even if that message did not actually opt into those hooks through mailbox dispatch.","recommendation":"Require `msg.sender == address(mailbox)` for hooks whose security depends on mailbox state, or override `postDispatch` in those hooks to enforce mailbox-only access. Add single-use guards per message ID where duplicate execution would be unsafe.","evidence":"`AbstractPostDispatchHook.postDispatch` has no caller check. `MerkleTreeHook` and `AbstractMessageIdAuthHook` only verify that the supplied message matches `mailbox.latestDispatchedId()`, which any external caller can satisfy by replaying the just-emitted message bytes.","locations":["AUDIT_BUNDLE.txt:9226 (contracts/hooks/libs/AbstractPostDispatchHook.sol)","AUDIT_BUNDLE.txt:9489 (contracts/hooks/libs/AbstractMessageIdAuthHook.sol)","AUDIT_BUNDLE.txt:10753 (contracts/hooks/MerkleTreeHook.sol)"]},{"severity":"low","category":"other","title":"DestinationRecipientRoutingHook quotes the wrong hook for recipient-specific routes","exploit_scenario":"If the owner configures a `customHooks[destination][recipient]`, dispatch execution will route to that custom hook, but fee quoting still uses the destination-level hook from `DomainRoutingHook`. Users relying on `quoteDispatch` can underpay and have dispatches revert, making recipient-specific routes unusable unless callers manually overpay.","recommendation":"Override `_quoteDispatch` in `DestinationRecipientRoutingHook` so it resolves the same hook that `_postDispatch` will actually call, including recipient-specific overrides.","evidence":"`DestinationRecipientRoutingHook._postDispatch` consults `customHooks[destination][recipient]`, but inherited `DomainRoutingHook._quoteDispatch` only calls `_getConfiguredHook(message)`, which is destination-only and never checks the recipient override map.","locations":["AUDIT_BUNDLE.txt:11186 (contracts/hooks/routing/DomainRoutingHook.sol)","AUDIT_BUNDLE.txt:11238 (contracts/hooks/routing/DestinationRecipientRoutingHook.sol)"]}]}
View stderr
Adapter.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity ^0.8.13;



contract PortalAdapter is ILiquidityLayerAdapter, Router {
    /// @notice The Portal TokenBridge contract.
    IPortalTokenBridge public portalTokenBridge;

    /// @notice The LiquidityLayerRouter contract.
    address public liquidityLayerRouter;

    /// @notice Hyperlane domain => Wormhole domain.
    mapping(uint32 => uint16) public hyperlaneDomainToWormholeDomain;
    /// @notice transferId => token address
    mapping(bytes32 => address) public portalTransfersProcessed;

    // We could technically use Portal's sequence number here but it doesn't
    // get passed through, so we would have to parse the VAA twice
    // 224 bits should be large enough and allows us to pack into a single slot
    // with a Hyperlane domain
    uint224 public nonce = 0;

    constructor(address _mailbox) Router(_mailbox) {}

    /**
     * @notice Emits the nonce of the Portal message when a token is bridged.
     * @param nonce The nonce of the Portal message.
     * @param portalSequence The sequence of the Portal message.
     * @param destination The hyperlane domain of the destination
     */
    event BridgedToken(
        uint256 nonce,
        uint64 portalSequence,
        uint32 destination
    );

    /**
     * @notice Emitted when the Hyperlane domain to Wormhole domain mapping is updated.
     * @param hyperlaneDomain The Hyperlane domain.
     * @param wormholeDomain The Wormhole domain.
     */
    event DomainAdded(uint32 indexed hyperlaneDomain, uint32 wormholeDomain);

    modifier onlyLiquidityLayerRouter() {
        require(msg.sender == liquidityLayerRouter, "!liquidityLayerRouter");
        _;
    }

    /**
     * @param _owner The new owner.
     * @param _portalTokenBridge The Portal TokenBridge contract.
     * @param _liquidityLayerRouter The LiquidityLayerRouter contract.
     */
    function initialize(
        address _owner,
        address _portalTokenBridge,
        address _liquidityLayerRouter
    ) public initializer {
        // Transfer ownership of the contract to deployer
        _transferOwnership(_owner);

        portalTokenBridge = IPortalTokenBridge(_portalTokenBridge);
        liquidityLayerRouter = _liquidityLayerRouter;
    }

    /**
     * Sends tokens as requested by the router
     * @param _destinationDomain The hyperlane domain of the destination
     * @param _token The token address
     * @param _amount The amount of tokens to send
     */
    function sendTokens(
        uint32 _destinationDomain,
        bytes32, // _recipientAddress, unused
        address _token,
        uint256 _amount
    ) external onlyLiquidityLayerRouter returns (bytes memory) {
        nonce = nonce + 1;
        uint16 _wormholeDomain = hyperlaneDomainToWormholeDomain[
            _destinationDomain
        ];

        bytes32 _remoteRouter = _mustHaveRemoteRouter(_destinationDomain);

        // Approve the token to Portal. We assume that the LiquidityLayerRouter
        // has already transferred the token to this contract.
        require(
            IERC20(_token).approve(address(portalTokenBridge), _amount),
            "!approval"
        );

        uint64 _portalSequence = portalTokenBridge.transferTokensWithPayload(
            _token,
            _amount,
            _wormholeDomain,
            _remoteRouter,
            // Nonce for grouping Portal messages in the same tx, not relevant for us
            // https://book.wormhole.com/technical/evm/coreLayer.html#emitting-a-vaa
            0,
            // Portal Payload used in completeTransfer
            abi.encode(localDomain, nonce)
        );

        emit BridgedToken(nonce, _portalSequence, _destinationDomain);
        return abi.encode(nonce);
    }

    /**
     * Sends the tokens to the recipient as requested by the router
     * @param _originDomain The hyperlane domain of the origin
     * @param _recipient The address of the recipient
     * @param _amount The amount of tokens to send
     * @param _adapterData The adapter data from the origin chain, containing the nonce
     */
    function receiveTokens(
        uint32 _originDomain, // Hyperlane domain
        address _recipient,
        uint256 _amount,
        bytes calldata _adapterData // The adapter data from the message
    ) external onlyLiquidityLayerRouter returns (address, uint256) {
        // Get the nonce information from the adapterData
        uint224 _nonce = abi.decode(_adapterData, (uint224));

        address _tokenAddress = portalTransfersProcessed[
            transferId(_originDomain, _nonce)
        ];

        require(
            _tokenAddress != address(0x0),
            "Portal Transfer has not yet been completed"
        );

        IERC20 _token = IERC20(_tokenAddress);

        // Transfer the token out to the recipient
        // TODO: use safeTransfer
        // Portal doesn't charge any fee, so we can safely transfer out the
        // exact amount that was bridged over.
        require(_token.transfer(_recipient, _amount), "!transfer out");
        return (_tokenAddress, _amount);
    }

    /**
     * Completes the Portal transfer which sends the funds to this adapter.
     * The router can call receiveTokens to move those funds to the ultimate recipient.
     * @param encodedVm The VAA from the Wormhole Guardians
     */
    function completeTransfer(bytes memory encodedVm) public {
        bytes memory _tokenBridgeTransferWithPayload = portalTokenBridge
            .completeTransferWithPayload(encodedVm);
        IPortalTokenBridge.TransferWithPayload
            memory _transfer = portalTokenBridge.parseTransferWithPayload(
                _tokenBridgeTransferWithPayload
            );

        (uint32 _originDomain, uint224 _nonce) = abi.decode(
            _transfer.payload,
            (uint32, uint224)
        );

        // Logic taken from here https://github.com/wormhole-foundation/wormhole/blob/dev.v2/ethereum/contracts/bridge/Bridge.sol#L503
        address tokenAddress = _transfer.tokenChain ==
            hyperlaneDomainToWormholeDomain[localDomain]
            ? TypeCasts.bytes32ToAddress(_transfer.tokenAddress)
            : portalTokenBridge.wrappedAsset(
                _transfer.tokenChain,
                _transfer.tokenAddress
            );

        portalTransfersProcessed[
            transferId(_originDomain, _nonce)
        ] = tokenAddress;
    }

    // This contract is only a Router to be aware of remote router addresses,
    // and doesn't actually send/handle Hyperlane messages directly
    function _handle(
        uint32, // origin
        bytes32, // sender
        bytes calldata // message
    ) internal pure override {
        revert("No messages expected");
    }

    function addDomain(
        uint32 _hyperlaneDomain,
        uint16 _wormholeDomain
    ) external onlyOwner {
        hyperlaneDomainToWormholeDomain[_hyperlaneDomain] = _wormholeDomain;

        emit DomainAdded(_hyperlaneDomain, _wormholeDomain);
    }

    /**
     * The key that is used to track fulfilled Portal transfers
     * @param _hyperlaneDomain The hyperlane of the origin
     * @param _nonce The nonce of the adapter on the origin
     */
    function transferId(
        uint32 _hyperlaneDomain,
        uint224 _nonce
    ) public pure returns (bytes32) {
        return bytes32(abi.encodePacked(_hyperlaneDomain, _nonce));
    }
}


// File contracts/interfaces/ILiquidityLayerMessageRecipient.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity ^0.8.13;

interface ILiquidityLayerMessageRecipient {
    function handleWithTokens(
        uint32 _origin,
        bytes32 _sender,
        bytes calldata _message,
        address _token,
        uint256 _amount
    ) external;
}


// File contracts/interfaces/ILiquidityLayerRouter.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity >=0.6.11;

interface ILiquidityLayerRouter {
    function dispatchWithTokens(
        uint32 _destinationDomain,
        bytes32 _recipientAddress,
        address _token,
        uint256 _amount,
        string calldata _bridge,
        bytes calldata _messageBody
    ) external returns (bytes32);
}


// File contracts/middleware/liquidity-layer/LiquidityLayerRouter.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity ^0.8.13;





contract LiquidityLayerRouter is Router, ILiquidityLayerRouter {
    using SafeERC20 for IERC20;

    // Token bridge => adapter address
    mapping(string => address) public liquidityLayerAdapters;

    event LiquidityLayerAdapterSet(string indexed bridge, address adapter);

    constructor(address _mailbox) Router(_mailbox) {}

    /**
     * @notice Initializes the Router contract with Hyperlane core contracts and the address of the interchain security module.
     * @param _interchainGasPaymaster The address of the interchain gas paymaster contract.
     * @param _interchainSecurityModule The address of the interchain security module contract.
     * @param _owner The address with owner privileges.
     */
    function initialize(
        address _interchainGasPaymaster,
        address _interchainSecurityModule,
        address _owner
    ) external initializer {
        _MailboxClient_initialize(
            _interchainGasPaymaster,
            _interchainSecurityModule,
            _owner
        );
    }

    function dispatchWithTokens(
        uint32 _destinationDomain,
        bytes32 _recipientAddress,
        address _token,
        uint256 _amount,
        string calldata _bridge,
        bytes calldata _messageBody
    ) external returns (bytes32) {
        ILiquidityLayerAdapter _adapter = _getAdapter(_bridge);

        // Transfer the tokens to the adapter
        IERC20(_token).safeTransferFrom(msg.sender, address(_adapter), _amount);

        // Reverts if the bridge was unsuccessful.
        // Gets adapter-specific data that is encoded into the message
        // ultimately sent via Hyperlane.
        bytes memory _adapterData = _adapter.sendTokens(
            _destinationDomain,
            _recipientAddress,
            _token,
            _amount
        );

        // The user's message "wrapped" with metadata required by this middleware
        bytes memory _messageWithMetadata = abi.encode(
            TypeCasts.addressToBytes32(msg.sender),
            _recipientAddress, // The "user" recipient
            _amount, // The amount of the tokens sent over the bridge
            _bridge, // The destination token bridge ID
            _adapterData, // The adapter-specific data
            _messageBody // The "user" message
        );

        // Dispatch the _messageWithMetadata to the destination's LiquidityLayerRouter.
        return _dispatch(_destinationDomain, _messageWithMetadata);
    }

    // Handles a message from an enrolled remote LiquidityLayerRouter
    function _handle(
        uint32 _origin,
        bytes32, // _sender, unused
        bytes calldata _message
    ) internal override {
        // Decode the message with metadata, "unwrapping" the user's message body
        (
            bytes32 _originalSender,
            bytes32 _userRecipientAddress,
            uint256 _amount,
            string memory _bridge,
            bytes memory _adapterData,
            bytes memory _userMessageBody
        ) = abi.decode(
                _message,
                (bytes32, bytes32, uint256, string, bytes, bytes)
            );

        ILiquidityLayerMessageRecipient _userRecipient = ILiquidityLayerMessageRecipient(
                TypeCasts.bytes32ToAddress(_userRecipientAddress)
            );

        // Reverts if the adapter hasn't received the bridged tokens yet
        (address _token, uint256 _receivedAmount) = _getAdapter(_bridge)
            .receiveTokens(
                _origin,
                address(_userRecipient),
                _amount,
                _adapterData
            );

        if (_userMessageBody.length > 0) {
            _userRecipient.handleWithTokens(
                _origin,
                _originalSender,
                _userMessageBody,
                _token,
                _receivedAmount
            );
        }
    }

    function setLiquidityLayerAdapter(
        string calldata _bridge,
        address _adapter
    ) external onlyOwner {
        liquidityLayerAdapters[_bridge] = _adapter;
        emit LiquidityLayerAdapterSet(_bridge, _adapter);
    }

    function _getAdapter(
        string memory _bridge
    ) internal view returns (ILiquidityLayerAdapter _adapter) {
        _adapter = ILiquidityLayerAdapter(liquidityLayerAdapters[_bridge]);
        // Require the adapter to have been set
        require(address(_adapter) != address(0), "No adapter found for bridge");
    }

exec
/bin/bash -lc "sed -n '15181,17410p' AUDIT_BUNDLE.txt" in /tmp/codex-3gxliacl
 succeeded in 0ms:
}


// File contracts/mock/MockToken.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity ^0.8.13;

contract MockToken is ERC20Upgradeable {
    function mint(address account, uint256 amount) external {
        _mint(account, amount);
    }

    function burn(uint256 _amount) external {
        _burn(msg.sender, _amount);
    }
}


// File contracts/mock/MockCircleMessageTransmitter.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity ^0.8.13;


contract MockCircleMessageTransmitter is ICircleMessageTransmitter {
    mapping(bytes32 => bool) processedNonces;
    MockToken token;

    constructor(MockToken _token) {
        token = _token;
    }

    function receiveMessage(
        bytes memory,
        bytes calldata
    ) external pure returns (bool success) {
        success = true;
    }

    function hashSourceAndNonce(
        uint32 _source,
        uint64 _nonce
    ) public pure returns (bytes32) {
        return keccak256(abi.encodePacked(_source, _nonce));
    }

    function process(
        bytes32 _nonceId,
        address _recipient,
        uint256 _amount
    ) public {
        processedNonces[_nonceId] = true;
        token.mint(_recipient, _amount);
    }

    function usedNonces(bytes32 _nonceId) external view returns (bool) {
        return processedNonces[_nonceId];
    }
}


// File contracts/mock/MockCircleTokenMessenger.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity ^0.8.13;


contract MockCircleTokenMessenger is ITokenMessenger {
    uint64 public nextNonce = 0;
    MockToken token;

    constructor(MockToken _token) {
        token = _token;
    }

    function depositForBurn(
        uint256 _amount,
        uint32,
        bytes32,
        address _burnToken
    ) external returns (uint64 _nonce) {
        nextNonce = nextNonce + 1;
        _nonce = nextNonce;
        require(address(token) == _burnToken);
        token.transferFrom(msg.sender, address(this), _amount);
        token.burn(_amount);
    }

    function depositForBurnWithCaller(
        uint256,
        uint32,
        bytes32,
        address,
        bytes32
    ) external returns (uint64 _nonce) {
        nextNonce = nextNonce + 1;
        _nonce = nextNonce;
    }
}


// File contracts/mock/MockERC5164.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity ^0.8.13;

contract MockMessageDispatcher is IMessageDispatcher {
    function dispatchMessage(
        uint256 toChainId,
        address to,
        bytes calldata data
    ) external returns (bytes32) {
        bytes32 messageId = keccak256(abi.encodePacked(toChainId, to, data));

        // simulate a successful dispatch
        emit MessageDispatched(messageId, msg.sender, toChainId, to, data);

        return messageId;
    }
}

contract MockMessageExecutor {
    event MessageIdExecuted(
        uint256 indexed fromChainId,
        bytes32 indexed messageId
    );
}


// File contracts/test/TestIsm.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity >=0.6.11;

contract TestIsm is IInterchainSecurityModule {
    uint8 public moduleType = uint8(Types.NULL);

    bool verifyResult = true;

    function setVerify(bool _verify) public {
        verifyResult = _verify;
    }

    function verify(bytes calldata, bytes calldata) public view returns (bool) {
        return verifyResult;
    }
}


// File contracts/test/TestPostDispatchHook.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity >=0.8.0;


contract TestPostDispatchHook is AbstractPostDispatchHook {
    // ============ Public Storage ============

    // test fees for quoteDispatch
    uint256 public fee = 0;

    // ============ External Functions ============

    /// @inheritdoc IPostDispatchHook
    function hookType() external pure override returns (uint8) {
        return uint8(IPostDispatchHook.Types.UNUSED);
    }

    function supportsMetadata(
        bytes calldata
    ) public pure override returns (bool) {
        return true;
    }

    function setFee(uint256 _fee) external {
        fee = _fee;
    }

    // ============ Internal functions ============
    function _postDispatch(
        bytes calldata,
        /*metadata*/
        bytes calldata /*message*/
    ) internal pure override {
        // test - empty
    }

    function _quoteDispatch(
        bytes calldata,
        /*metadata*/
        bytes calldata /*message*/
    ) internal view override returns (uint256) {
        return fee;
    }
}


// File contracts/mock/MockMailbox.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity ^0.8.0;








contract MockMailbox is Mailbox {
    using Message for bytes;

    uint32 public inboundUnprocessedNonce = 0;
    uint32 public inboundProcessedNonce = 0;

    mapping(uint32 => MockMailbox) public remoteMailboxes;
    mapping(uint256 => bytes) public inboundMessages;

    constructor(uint32 _domain) Mailbox(_domain) {
        TestIsm ism = new TestIsm();
        defaultIsm = ism;

        TestPostDispatchHook hook = new TestPostDispatchHook();
        defaultHook = hook;
        requiredHook = hook;

        _transferOwnership(msg.sender);
        _disableInitializers();
    }

    function addRemoteMailbox(uint32 _domain, MockMailbox _mailbox) external {
        remoteMailboxes[_domain] = _mailbox;
    }

    function dispatch(
        uint32 destinationDomain,
        bytes32 recipientAddress,
        bytes calldata messageBody,
        bytes calldata metadata,
        IPostDispatchHook hook
    ) public payable override returns (bytes32) {
        bytes memory message = _buildMessage(
            destinationDomain,
            recipientAddress,
            messageBody
        );
        bytes32 id = super.dispatch(
            destinationDomain,
            recipientAddress,
            messageBody,
            metadata,
            hook
        );

        MockMailbox _destinationMailbox = remoteMailboxes[destinationDomain];
        require(
            address(_destinationMailbox) != address(0),
            "Missing remote mailbox"
        );
        _destinationMailbox.addInboundMessage(message);

        return id;
    }

    function addInboundMessage(bytes calldata message) external {
        inboundMessages[inboundUnprocessedNonce] = message;
        inboundUnprocessedNonce++;
    }

    function processNextInboundMessage() public {
        bytes memory _message = inboundMessages[inboundProcessedNonce];
        Mailbox(address(this)).process("", _message);
        inboundProcessedNonce++;
    }
}


// File contracts/test/TestInterchainGasPaymaster.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity >=0.8.0;

// ============ Internal Imports ============

contract TestInterchainGasPaymaster is InterchainGasPaymaster {
    uint256 public constant gasPrice = 10;

    constructor() {
        initialize(msg.sender, msg.sender);
    }

    function quoteGasPayment(
        uint32,
        uint256 gasAmount
    ) public pure override returns (uint256) {
        return gasPrice * gasAmount;
    }
}


// File contracts/mock/MockHyperlaneEnvironment.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity ^0.8.13;



contract MockHyperlaneEnvironment {
    uint32 originDomain;
    uint32 destinationDomain;

    mapping(uint32 => MockMailbox) public mailboxes;
    mapping(uint32 => TestInterchainGasPaymaster) public igps;
    mapping(uint32 => IInterchainSecurityModule) public isms;

    constructor(uint32 _originDomain, uint32 _destinationDomain) {
        originDomain = _originDomain;
        destinationDomain = _destinationDomain;

        MockMailbox originMailbox = new MockMailbox(_originDomain);
        MockMailbox destinationMailbox = new MockMailbox(_destinationDomain);

        originMailbox.addRemoteMailbox(_destinationDomain, destinationMailbox);
        destinationMailbox.addRemoteMailbox(_originDomain, originMailbox);

        isms[originDomain] = new TestIsm();
        isms[destinationDomain] = new TestIsm();

        originMailbox.setDefaultIsm(address(isms[originDomain]));
        destinationMailbox.setDefaultIsm(address(isms[destinationDomain]));

        igps[originDomain] = new TestInterchainGasPaymaster();
        igps[destinationDomain] = new TestInterchainGasPaymaster();

        originMailbox.transferOwnership(msg.sender);
        destinationMailbox.transferOwnership(msg.sender);

        mailboxes[_originDomain] = originMailbox;
        mailboxes[_destinationDomain] = destinationMailbox;
    }

    function processNextPendingMessage() public {
        mailboxes[destinationDomain].processNextInboundMessage();
    }

    function processNextPendingMessageFromDestination() public {
        mailboxes[originDomain].processNextInboundMessage();
    }
}


// File contracts/mock/MockPortalBridge.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity ^0.8.13;



contract MockPortalBridge is IPortalTokenBridge {
    uint256 nextNonce = 0;
    MockToken token;

    constructor(MockToken _token) {
        token = _token;
    }

    function transferTokensWithPayload(
        address,
        uint256 amount,
        uint16,
        bytes32,
        uint32,
        bytes memory
    ) external payable returns (uint64 sequence) {
        nextNonce = nextNonce + 1;
        token.transferFrom(msg.sender, address(this), amount);
        token.burn(amount);
        return uint64(nextNonce);
    }

    function wrappedAsset(uint16, bytes32) external view returns (address) {
        return address(token);
    }

    function isWrappedAsset(address) external pure returns (bool) {
        return true;
    }

    function completeTransferWithPayload(
        bytes memory encodedVm
    ) external returns (bytes memory) {
        (uint32 _originDomain, uint224 _nonce, uint256 _amount) = abi.decode(
            encodedVm,
            (uint32, uint224, uint256)
        );

        token.mint(msg.sender, _amount);
        // Format it so that parseTransferWithPayload returns the desired payload
        return
            abi.encode(
                TypeCasts.addressToBytes32(address(token)),
                adapterData(_originDomain, _nonce, address(token))
            );
    }

    function parseTransferWithPayload(
        bytes memory encoded
    ) external pure returns (TransferWithPayload memory transfer) {
        (bytes32 tokenAddress, bytes memory payload) = abi.decode(
            encoded,
            (bytes32, bytes)
        );
        transfer.payload = payload;
        transfer.tokenAddress = tokenAddress;
    }

    function adapterData(
        uint32 _originDomain,
        uint224 _nonce,
        address _token
    ) public pure returns (bytes memory) {
        return
            abi.encode(
                _originDomain,
                _nonce,
                TypeCasts.addressToBytes32(_token)
            );
    }

    function mockPortalVaa(
        uint32 _originDomain,
        uint224 _nonce,
        uint256 _amount
    ) public pure returns (bytes memory) {
        return abi.encode(_originDomain, _nonce, _amount);
    }
}


// File contracts/test/ERC20Test.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity >=0.8.0;

contract ERC20Test is ERC20 {
    uint8 public immutable _decimals;

    constructor(
        string memory name,
        string memory symbol,
        uint256 totalSupply,
        uint8 __decimals
    ) ERC20(name, symbol) {
        _decimals = __decimals;
        _mint(msg.sender, totalSupply);
    }

    function decimals() public view override returns (uint8) {
        return _decimals;
    }
}


// File contracts/test/ERC721Test.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity >=0.8.0;

contract ERC721Test is ERC721Enumerable {
    constructor(
        string memory name,
        string memory symbol,
        uint256 _mintAmount
    ) ERC721(name, symbol) {
        for (uint256 i = 0; i < _mintAmount; i++) {
            _mint(msg.sender, i);
        }
    }

    function _baseURI() internal pure override returns (string memory) {
        return "TEST-BASE-URI";
    }
}


// File contracts/test/TestRecipient.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity >=0.8.0;


contract TestRecipient is
    Ownable,
    IMessageRecipient,
    ISpecifiesInterchainSecurityModule
{
    IInterchainSecurityModule public interchainSecurityModule;
    bytes32 public lastSender;
    bytes public lastData;

    address public lastCaller;
    string public lastCallMessage;

    event ReceivedMessage(
        uint32 indexed origin,
        bytes32 indexed sender,
        uint256 indexed value,
        string message
    );

    event ReceivedCall(address indexed caller, uint256 amount, string message);

    function handle(
        uint32 _origin,
        bytes32 _sender,
        bytes calldata _data
    ) external payable virtual override {
        emit ReceivedMessage(_origin, _sender, msg.value, string(_data));
        lastSender = _sender;
        lastData = _data;
    }

    function fooBar(uint256 amount, string calldata message) external {
        emit ReceivedCall(msg.sender, amount, message);
        lastCaller = msg.sender;
        lastCallMessage = message;
    }

    function setInterchainSecurityModule(address _ism) external onlyOwner {
        interchainSecurityModule = IInterchainSecurityModule(_ism);
    }
}


// File contracts/test/LightTestRecipient.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity >=0.6.11;

contract LightTestRecipient is TestRecipient {
    // solhint-disable-next-line no-empty-blocks
    function handle(
        uint32 _origin,
        bytes32 _sender,
        bytes calldata _data
    ) external payable override {
        // do nothing
    }
}


// File contracts/test/TestGasRouter.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity >=0.6.11;

contract TestGasRouter is GasRouter {
    constructor(address _mailbox) GasRouter(_mailbox) {}

    function dispatch(uint32 _destination, bytes memory _msg) external payable {
        _dispatch(_destination, _msg);
    }

    function _handle(uint32, bytes32, bytes calldata) internal pure override {}
}


// File contracts/test/TestLiquidityLayerMessageRecipient.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity ^0.8.13;

contract TestLiquidityLayerMessageRecipient is ILiquidityLayerMessageRecipient {
    event HandledWithTokens(
        uint32 origin,
        bytes32 sender,
        bytes message,
        address token,
        uint256 amount
    );

    function handleWithTokens(
        uint32 _origin,
        bytes32 _sender,
        bytes calldata _message,
        address _token,
        uint256 _amount
    ) external {
        emit HandledWithTokens(_origin, _sender, _message, _token, _amount);
    }
}


// File contracts/test/TestMailbox.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity >=0.8.0;





contract TestMailbox is Mailbox {
    using TypeCasts for bytes32;

    constructor(uint32 _localDomain) Mailbox(_localDomain) {
        _transferOwnership(msg.sender);
    }

    function testHandle(
        uint32 _origin,
        bytes32 _sender,
        bytes32 _recipient,
        bytes calldata _body
    ) external {
        IMessageRecipient(_recipient.bytes32ToAddress()).handle(
            _origin,
            _sender,
            _body
        );
    }

    function buildOutboundMessage(
        uint32 destinationDomain,
        bytes32 recipientAddress,
        bytes calldata body
    ) external view returns (bytes memory) {
        return _buildMessage(destinationDomain, recipientAddress, body);
    }

    function buildInboundMessage(
        uint32 originDomain,
        bytes32 recipientAddress,
        bytes32 senderAddress,
        bytes calldata body
    ) external view returns (bytes memory) {
        return
            Message.formatMessage(
                VERSION,
                nonce,
                originDomain,
                senderAddress,
                localDomain,
                recipientAddress,
                body
            );
    }

    function updateLatestDispatchedId(bytes32 _id) external {
        latestDispatchedId = _id;
    }
}


// File contracts/test/TestMerkle.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity >=0.8.0;

contract TestMerkle {
    using MerkleLib for MerkleLib.Tree;

    MerkleLib.Tree public tree;

    // solhint-disable-next-line no-empty-blocks
    constructor() {}

    function insert(bytes32 _node) external {
        tree.insert(_node);
    }

    function branchRoot(
        bytes32 _leaf,
        bytes32[32] calldata _proof,
        uint256 _index
    ) external pure returns (bytes32 _node) {
        return MerkleLib.branchRoot(_leaf, _proof, _index);
    }

    /**
     * @notice Returns the number of inserted leaves in the tree
     */
    function count() public view returns (uint256) {
        return tree.count;
    }

    function root() public view returns (bytes32) {
        return tree.root();
    }
}


// File contracts/test/TestMerkleTreeHook.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity >=0.8.0;


contract TestMerkleTreeHook is MerkleTreeHook {
    using MerkleLib for MerkleLib.Tree;

    constructor(address _mailbox) MerkleTreeHook(_mailbox) {}

    function proof() external view returns (bytes32[32] memory) {
        bytes32[32] memory _zeroes = MerkleLib.zeroHashes();
        uint256 _index = _tree.count - 1;
        bytes32[32] memory _proof;

        for (uint256 i = 0; i < 32; i++) {
            uint256 _ithBit = (_index >> i) & 0x01;
            if (_ithBit == 1) {
                _proof[i] = _tree.branch[i];
            } else {
                _proof[i] = _zeroes[i];
            }
        }
        return _proof;
    }

    function insert(bytes32 _id) external {
        _tree.insert(_id);
    }
}


// File contracts/test/TestMessage.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity >=0.6.11;

contract TestMessage {
    using Message for bytes;

    function version(
        bytes calldata _message
    ) external pure returns (uint32 _version) {
        return _message.version();
    }

    function nonce(
        bytes calldata _message
    ) external pure returns (uint256 _nonce) {
        return _message.nonce();
    }

    function body(
        bytes calldata _message
    ) external pure returns (bytes calldata _body) {
        return _message.body();
    }

    function origin(
        bytes calldata _message
    ) external pure returns (uint32 _origin) {
        return _message.origin();
    }

    function sender(
        bytes calldata _message
    ) external pure returns (bytes32 _sender) {
        return _message.sender();
    }

    function destination(
        bytes calldata _message
    ) external pure returns (uint32 _destination) {
        return _message.destination();
    }

    function recipient(
        bytes calldata _message
    ) external pure returns (bytes32 _recipient) {
        return _message.recipient();
    }

    function recipientAddress(
        bytes calldata _message
    ) external pure returns (address _recipient) {
        return _message.recipientAddress();
    }

    function id(bytes calldata _message) external pure returns (bytes32) {
        return _message.id();
    }
}


// File contracts/test/TestQuery.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity ^0.8.13;



contract TestQuery {
    InterchainQueryRouter public router;

    event Owner(uint256, address);

    constructor(address _router) {
        router = InterchainQueryRouter(_router);
    }

    /**
     * @dev Fetches owner of InterchainQueryRouter on provided domain and passes along with provided secret to `this.receiveRouterOwner`
     */
    function queryRouterOwner(uint32 domain, uint256 secret) external {
        address target = TypeCasts.bytes32ToAddress(router.routers(domain));
        CallLib.StaticCallWithCallback[]
            memory calls = new CallLib.StaticCallWithCallback[](1);
        calls[0] = CallLib.build(
            target,
            abi.encodeWithSelector(Ownable.owner.selector),
            abi.encodeWithSelector(this.receiveRouterOwner.selector, secret)
        );
        router.query(domain, calls);
    }

    /**
     * @dev `msg.sender` must be restricted to `this.router` to prevent any local account from spoofing query data.
     */
    function receiveRouterOwner(uint256 secret, address owner) external {
        require(msg.sender == address(router), "TestQuery: not from router");
        emit Owner(secret, owner);
    }
}


// File contracts/test/TestQuerySender.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity >=0.8.0;


contract TestQuerySender {
    InterchainQueryRouter queryRouter;

    address public lastAddressResult;
    uint256 public lastUint256Result;
    bytes32 public lastBytes32Result;

    event ReceivedAddressResult(address result);
    event ReceivedUint256Result(uint256 result);
    event ReceivedBytes32Result(bytes32 result);

    function initialize(address _queryRouterAddress) external {
        queryRouter = InterchainQueryRouter(_queryRouterAddress);
    }

    function queryAddress(
        uint32 _destinationDomain,
        address _target,
        bytes calldata _targetData,
        uint256 _gasAmount
    ) external payable {
        queryAndPayFor(
            _destinationDomain,
            _target,
            _targetData,
            this.handleQueryAddressResult.selector,
            _gasAmount
        );
    }

    function handleQueryAddressResult(address _result) external {
        emit ReceivedAddressResult(_result);
        lastAddressResult = _result;
    }

    function queryUint256(
        uint32 _destinationDomain,
        address _target,
        bytes calldata _targetData,
        uint256 _gasAmount
    ) external payable {
        queryAndPayFor(
            _destinationDomain,
            _target,
            _targetData,
            this.handleQueryUint256Result.selector,
            _gasAmount
        );
    }

    function handleQueryUint256Result(uint256 _result) external {
        emit ReceivedUint256Result(_result);
        lastUint256Result = _result;
    }

    function queryBytes32(
        uint32 _destinationDomain,
        address _target,
        bytes calldata _targetData,
        uint256 _gasAmount
    ) external payable {
        queryAndPayFor(
            _destinationDomain,
            _target,
            _targetData,
            this.handleQueryBytes32Result.selector,
            _gasAmount
        );
    }

    function handleQueryBytes32Result(bytes32 _result) external {
        emit ReceivedBytes32Result(_result);
        lastBytes32Result = _result;
    }

    function queryAndPayFor(
        uint32 _destinationDomain,
        address _target,
        bytes calldata _targetData,
        bytes4 _callbackSelector,
        uint256 /*_gasAmount*/
    ) internal {
        queryRouter.query(
            _destinationDomain,
            _target,
            _targetData,
            abi.encodePacked(_callbackSelector)
        );
    }
}


// File contracts/test/TestRouter.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity >=0.6.11;

contract TestRouter is Router {
    event InitializeOverload();

    constructor(address _mailbox) Router(_mailbox) {}

    function initialize(
        address _hook,
        address _interchainSecurityModule
    ) public initializer {
        _MailboxClient_initialize(_hook, _interchainSecurityModule, msg.sender);
    }

    function _handle(uint32, bytes32, bytes calldata) internal pure override {}

    function isRemoteRouter(
        uint32 _domain,
        bytes32 _potentialRemoteRouter
    ) external view returns (bool) {
        return _isRemoteRouter(_domain, _potentialRemoteRouter);
    }

    function mustHaveRemoteRouter(
        uint32 _domain
    ) external view returns (bytes32) {
        return _mustHaveRemoteRouter(_domain);
    }

    function dispatch(uint32 _destination, bytes memory _msg) external payable {
        _dispatch(_destination, _msg);
    }
}


// File contracts/test/TestSendReceiver.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity >=0.8.0;





contract TestSendReceiver is IMessageRecipient {
    using TypeCasts for address;

    uint256 public constant HANDLE_GAS_AMOUNT = 50_000;

    event Handled(bytes32 blockHash);

    function dispatchToSelf(
        IMailbox _mailbox,
        uint32 _destinationDomain,
        bytes calldata _messageBody
    ) external payable {
        // TODO: handle topping up?
        _mailbox.dispatch{value: msg.value}(
            _destinationDomain,
            address(this).addressToBytes32(),
            _messageBody
        );
    }

    function dispatchToSelf(
        IMailbox _mailbox,
        uint32 _destinationDomain,
        bytes calldata _messageBody,
        IPostDispatchHook hook
    ) external payable {
        // TODO: handle topping up?
        _mailbox.dispatch{value: msg.value}(
            _destinationDomain,
            address(this).addressToBytes32(),
            _messageBody,
            bytes(""),
            hook
        );
    }

    function handle(uint32, bytes32, bytes calldata) external payable override {
        bytes32 blockHash = previousBlockHash();
        bool isBlockHashEndIn0 = uint256(blockHash) % 16 == 0;
        require(!isBlockHashEndIn0, "block hash ends in 0");
        emit Handled(blockHash);
    }

    function previousBlockHash() internal view returns (bytes32) {
        return blockhash(block.number - 1);
    }
}


// File contracts/test/TestTokenRecipient.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity >=0.8.0;

contract TestTokenRecipient is ILiquidityLayerMessageRecipient {
    bytes32 public lastSender;
    bytes public lastData;
    address public lastToken;
    uint256 public lastAmount;

    address public lastCaller;
    string public lastCallMessage;

    event ReceivedMessage(
        uint32 indexed origin,
        bytes32 indexed sender,
        string message,
        address token,
        uint256 amount
    );

    event ReceivedCall(address indexed caller, uint256 amount, string message);

    function handleWithTokens(
        uint32 _origin,
        bytes32 _sender,
        bytes calldata _data,
        address _token,
        uint256 _amount
    ) external override {
        emit ReceivedMessage(_origin, _sender, string(_data), _token, _amount);
        lastSender = _sender;
        lastData = _data;
        lastToken = _token;
        lastAmount = _amount;
    }

    function fooBar(uint256 amount, string calldata message) external {
        emit ReceivedCall(msg.sender, amount, message);
        lastCaller = msg.sender;
        lastCallMessage = message;
    }
}


// File contracts/token/libs/TokenMessage.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity >=0.8.0;

library TokenMessage {
    function format(
        bytes32 _recipient,
        uint256 _amount,
        bytes memory _metadata
    ) internal pure returns (bytes memory) {
        return abi.encodePacked(_recipient, _amount, _metadata);
    }

    function recipient(bytes calldata message) internal pure returns (bytes32) {
        return bytes32(message[0:32]);
    }

    function amount(bytes calldata message) internal pure returns (uint256) {
        return uint256(bytes32(message[32:64]));
    }

    // alias for ERC721
    function tokenId(bytes calldata message) internal pure returns (uint256) {
        return amount(message);
    }

    function metadata(
        bytes calldata message
    ) internal pure returns (bytes calldata) {
        return message[64:];
    }
}


// File contracts/token/libs/TokenRouter.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity >=0.8.0;




/**
 * @title Hyperlane Token Router that extends Router with abstract token (ERC20/ERC721) remote transfer functionality.
 * @author Abacus Works
 */
abstract contract TokenRouter is GasRouter {
    using TypeCasts for bytes32;
    using TypeCasts for address;
    using TokenMessage for bytes;

    /**
     * @dev Emitted on `transferRemote` when a transfer message is dispatched.
     * @param destination The identifier of the destination chain.
     * @param recipient The address of the recipient on the destination chain.
     * @param amount The amount of tokens burnt on the origin chain.
     */
    event SentTransferRemote(
        uint32 indexed destination,
        bytes32 indexed recipient,
        uint256 amount
    );

    /**
     * @dev Emitted on `_handle` when a transfer message is processed.
     * @param origin The identifier of the origin chain.
     * @param recipient The address of the recipient on the destination chain.
     * @param amount The amount of tokens minted on the destination chain.
     */
    event ReceivedTransferRemote(
        uint32 indexed origin,
        bytes32 indexed recipient,
        uint256 amount
    );

    constructor(address _mailbox) GasRouter(_mailbox) {}

    /**
     * @notice Transfers `_amountOrId` token to `_recipient` on `_destination` domain.
     * @dev Delegates transfer logic to `_transferFromSender` implementation.
     * @dev Emits `SentTransferRemote` event on the origin chain.
     * @param _destination The identifier of the destination chain.
     * @param _recipient The address of the recipient on the destination chain.
     * @param _amountOrId The amount or identifier of tokens to be sent to the remote recipient.
     * @return messageId The identifier of the dispatched message.
     */
    function transferRemote(
        uint32 _destination,
        bytes32 _recipient,
        uint256 _amountOrId
    ) external payable virtual returns (bytes32 messageId) {
        return
            _transferRemote(_destination, _recipient, _amountOrId, msg.value);
    }

    /**
     * @notice Transfers `_amountOrId` token to `_recipient` on `_destination` domain.
     * @dev Delegates transfer logic to `_transferFromSender` implementation.
     * @dev Emits `SentTransferRemote` event on the origin chain.
     * @param _destination The identifier of the destination chain.
     * @param _recipient The address of the recipient on the destination chain.
     * @param _amountOrId The amount or identifier of tokens to be sent to the remote recipient.
     * @param _gasPayment The amount of native token to pay for interchain gas.
     * @return messageId The identifier of the dispatched message.
     */
    function _transferRemote(
        uint32 _destination,
        bytes32 _recipient,
        uint256 _amountOrId,
        uint256 _gasPayment
    ) internal returns (bytes32 messageId) {
        bytes memory metadata = _transferFromSender(_amountOrId);
        messageId = _dispatch(
            _destination,
            _gasPayment,
            TokenMessage.format(_recipient, _amountOrId, metadata)
        );
        emit SentTransferRemote(_destination, _recipient, _amountOrId);
    }

    /**
     * @dev Should transfer `_amountOrId` of tokens from `msg.sender` to this token router.
     * @dev Called by `transferRemote` before message dispatch.
     * @dev Optionally returns `metadata` associated with the transfer to be passed in message.
     */
    function _transferFromSender(
        uint256 _amountOrId
    ) internal virtual returns (bytes memory metadata);

    /**
     * @notice Returns the balance of `account` on this token router.
     * @param account The address to query the balance of.
     * @return The balance of `account`.
     */
    function balanceOf(address account) external virtual returns (uint256);

    /**
     * @dev Mints tokens to recipient when router receives transfer message.
     * @dev Emits `ReceivedTransferRemote` event on the destination chain.
     * @param _origin The identifier of the origin chain.
     * @param _message The encoded remote transfer message containing the recipient address and amount.
     */
    function _handle(
        uint32 _origin,
        bytes32,
        bytes calldata _message
    ) internal virtual override {
        bytes32 recipient = _message.recipient();
        uint256 amount = _message.amount();
        bytes calldata metadata = _message.metadata();
        _transferTo(recipient.bytes32ToAddress(), amount, metadata);
        emit ReceivedTransferRemote(_origin, recipient, amount);
    }

    /**
     * @dev Should transfer `_amountOrId` of tokens from this token router to `_recipient`.
     * @dev Called by `handle` after message decoding.
     * @dev Optionally handles `metadata` associated with transfer passed in message.
     */
    function _transferTo(
        address _recipient,
        uint256 _amountOrId,
        bytes calldata metadata
    ) internal virtual;
}


// File contracts/token/HypERC20.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity >=0.8.0;

/**
 * @title Hyperlane ERC20 Token Router that extends ERC20 with remote transfer functionality.
 * @author Abacus Works
 * @dev Supply on each chain is not constant but the aggregate supply across all chains is.
 */
contract HypERC20 is ERC20Upgradeable, TokenRouter {
    uint8 private immutable _decimals;

    constructor(uint8 __decimals, address _mailbox) TokenRouter(_mailbox) {
        _decimals = __decimals;
    }

    /**
     * @notice Initializes the Hyperlane router, ERC20 metadata, and mints initial supply to deployer.
     * @param _totalSupply The initial supply of the token.
     * @param _name The name of the token.
     * @param _symbol The symbol of the token.
     */
    function initialize(
        uint256 _totalSupply,
        string memory _name,
        string memory _symbol
    ) external initializer {
        // Initialize ERC20 metadata
        __ERC20_init(_name, _symbol);
        _mint(msg.sender, _totalSupply);
    }

    function decimals() public view override returns (uint8) {
        return _decimals;
    }

    function balanceOf(
        address _account
    )
        public
        view
        virtual
        override(TokenRouter, ERC20Upgradeable)
        returns (uint256)
    {
        return ERC20Upgradeable.balanceOf(_account);
    }

    /**
     * @dev Burns `_amount` of token from `msg.sender` balance.
     * @inheritdoc TokenRouter
     */
    function _transferFromSender(
        uint256 _amount
    ) internal override returns (bytes memory) {
        _burn(msg.sender, _amount);
        return bytes(""); // no metadata
    }

    /**
     * @dev Mints `_amount` of token to `_recipient` balance.
     * @inheritdoc TokenRouter
     */
    function _transferTo(
        address _recipient,
        uint256 _amount,
        bytes calldata // no metadata
    ) internal virtual override {
        _mint(_recipient, _amount);
    }
}


// File contracts/token/libs/FastTokenRouter.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity >=0.8.0;


/**
 * @title Common FastTokenRouter functionality for ERC20 Tokens with remote transfer support.
 * @author Abacus Works
 */
abstract contract FastTokenRouter is TokenRouter {
    using TypeCasts for bytes32;
    using TokenMessage for bytes;

    uint256 public fastTransferId;
    // maps `fastTransferId` to the filler address.
    mapping(bytes32 => address) filledFastTransfers;

    /**
     * @dev delegates transfer logic to `_transferTo`.
     * @inheritdoc TokenRouter
     */
    function _handle(
        uint32 _origin,
        bytes32,
        bytes calldata _message
    ) internal virtual override {
        bytes32 recipient = _message.recipient();
        uint256 amount = _message.amount();
        bytes calldata metadata = _message.metadata();
        _transferTo(recipient.bytes32ToAddress(), amount, _origin, metadata);
        emit ReceivedTransferRemote(_origin, recipient, amount);
    }

    /**
     * @dev Transfers `_amount` of token to `_recipient`/`fastFiller` who provided LP.
     * @dev Called by `handle` after message decoding.
     */
    function _transferTo(
        address _recipient,
        uint256 _amount,
        uint32 _origin,
        bytes calldata _metadata
    ) internal virtual {
        address _tokenRecipient = _getTokenRecipient(
            _recipient,
            _amount,
            _origin,
            _metadata
        );

        _fastTransferTo(_tokenRecipient, _amount);
    }

    /**
     * @dev allows an external user to full an unfilled fast transfer order.
     * @param _recipient The recepient of the wrapped token on base chain.
     * @param _amount The amount of wrapped tokens that is being bridged.
     * @param _fastFee The fee the bridging entity will pay.
     * @param _fastTransferId Id assigned on the remote chain to uniquely identify the transfer.
     */
    function fillFastTransfer(
        address _recipient,
        uint256 _amount,
        uint256 _fastFee,
        uint32 _origin,
        uint256 _fastTransferId
    ) external virtual {
        bytes32 filledFastTransfersKey = _getFastTransfersKey(
            _origin,
            _fastTransferId,
            _amount,
            _fastFee,
            _recipient
        );
        require(
            filledFastTransfers[filledFastTransfersKey] == address(0),
            "request already filled"
        );

        filledFastTransfers[filledFastTransfersKey] = msg.sender;

        _fastRecieveFrom(msg.sender, _amount - _fastFee);
        _fastTransferTo(_recipient, _amount - _fastFee);
    }

    /**
     * @dev Transfers `_amountOrId` token to `_recipient` on `_destination` domain.
     * @dev Delegates transfer logic to `_fastTransferFromSender` implementation.
     * @dev Emits `SentTransferRemote` event on the origin chain.
     * @param _destination The identifier of the destination chain.
     * @param _recipient The address of the recipient on the destination chain.
     * @param _amountOrId The amount or identifier of tokens to be sent to the remote recipient.
     * @return messageId The identifier of the dispatched message.
     */
    function fastTransferRemote(
        uint32 _destination,
        bytes32 _recipient,
        uint256 _amountOrId,
        uint256 _fastFee
    ) public payable virtual returns (bytes32 messageId) {
        uint256 _fastTransferId = fastTransferId + 1;
        fastTransferId = _fastTransferId;
        bytes memory metadata = _fastTransferFromSender(
            _amountOrId,
            _fastFee,
            _fastTransferId
        );

        messageId = _dispatch(
            _destination,
            TokenMessage.format(_recipient, _amountOrId, metadata)
        );
        emit SentTransferRemote(_destination, _recipient, _amountOrId);
    }

    /**
     * @dev Burns `_amount` of token from `msg.sender` balance.
     * @dev Pays `_fastFee` of tokens to LP on source chain.
     * @dev Returns `fastFee` as bytes in the form of metadata.
     */
    function _fastTransferFromSender(
        uint256 _amount,
        uint256 _fastFee,
        uint256 _fastTransferId
    ) internal virtual returns (bytes memory) {
        _fastRecieveFrom(msg.sender, _amount);
        return abi.encode(_fastFee, _fastTransferId);
    }

    /**
     * @dev returns an address that indicates who should recieve the bridged tokens.
     * @dev if _fastFees was inlcuded and someone filled the order before the mailbox made the contract call, the filler gets the funds.
     */
    function _getTokenRecipient(
        address _recipient,
        uint256 _amount,
        uint32 _origin,
        bytes calldata _metadata
    ) internal view returns (address) {
        if (_metadata.length == 0) {
            return _recipient;
        }

        // decode metadata to extract `_fastFee` and `_fastTransferId`.
        (uint256 _fastFee, uint256 _fastTransferId) = abi.decode(
            _metadata,
            (uint256, uint256)
        );

        address _fillerAddress = filledFastTransfers[
            _getFastTransfersKey(
                _origin,
                _fastTransferId,
                _amount,
                _fastFee,
                _recipient
            )
        ];
        if (_fillerAddress != address(0)) {
            return _fillerAddress;
        }

        return _recipient;
    }

    /**
     * @dev generates the key for storing the filler address of fast transfers.
     */
    function _getFastTransfersKey(
        uint32 _origin,
        uint256 _fastTransferId,
        uint256 _amount,
        uint256 _fastFee,
        address _recipient
    ) internal pure returns (bytes32) {
        return
            keccak256(
                abi.encodePacked(
                    _origin,
                    _fastTransferId,
                    _amount,
                    _fastFee,
                    _recipient
                )
            );
    }

    /**
     * @dev Should transfer `_amount` of tokens to `_recipient`.
     * @dev The implementation is delegated.
     */
    function _fastTransferTo(
        address _recipient,
        uint256 _amount
    ) internal virtual;

    /**
     * @dev Should collect `amount` of tokens from `_sender`.
     * @dev The implementation is delegated.
     */
    function _fastRecieveFrom(
        address _sender,
        uint256 _amount
    ) internal virtual;
}


// File contracts/token/extensions/FastHypERC20.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity >=0.8.0;



/**
 * @title Hyperlane ERC20 Token Router that extends ERC20 with remote transfer functionality.
 * @author Abacus Works
 * @dev Supply on each chain is not constant but the aggregate supply across all chains is.
 */
contract FastHypERC20 is FastTokenRouter, HypERC20 {
    constructor(
        uint8 __decimals,
        address _mailbox
    ) HypERC20(__decimals, _mailbox) {}

    /**
     * @dev delegates transfer logic to `_transferTo`.
     * @inheritdoc TokenRouter
     */
    function _handle(
        uint32 _origin,
        bytes32 _sender,
        bytes calldata _message
    ) internal virtual override(FastTokenRouter, TokenRouter) {
        FastTokenRouter._handle(_origin, _sender, _message);
    }

    /**
     * @dev Mints `_amount` of tokens to `_recipient`.
     * @inheritdoc FastTokenRouter
     */
    function _fastTransferTo(
        address _recipient,
        uint256 _amount
    ) internal override {
        _mint(_recipient, _amount);
    }

    /**
     * @dev Burns `_amount` of tokens from `_recipient`.
     * @inheritdoc FastTokenRouter
     */
    function _fastRecieveFrom(
        address _sender,
        uint256 _amount
    ) internal override {
        _burn(_sender, _amount);
    }

    function balanceOf(
        address _account
    ) public view virtual override(HypERC20, TokenRouter) returns (uint256) {
        return ERC20Upgradeable.balanceOf(_account);
    }
}


// File contracts/token/HypERC20Collateral.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity >=0.8.0;




/**
 * @title Hyperlane ERC20 Token Collateral that wraps an existing ERC20 with remote transfer functionality.
 * @author Abacus Works
 */
contract HypERC20Collateral is TokenRouter {
    using SafeERC20 for IERC20;

    IERC20 public immutable wrappedToken;

    /**
     * @notice Constructor
     * @param erc20 Address of the token to keep as collateral
     */
    constructor(address erc20, address _mailbox) TokenRouter(_mailbox) {
        wrappedToken = IERC20(erc20);
    }

    function balanceOf(
        address _account
    ) external view override returns (uint256) {
        return wrappedToken.balanceOf(_account);
    }

    /**
     * @dev Transfers `_amount` of `wrappedToken` from `msg.sender` to this contract.
     * @inheritdoc TokenRouter
     */
    function _transferFromSender(
        uint256 _amount
    ) internal override returns (bytes memory) {
        wrappedToken.safeTransferFrom(msg.sender, address(this), _amount);
        return bytes(""); // no metadata
    }

    /**
     * @dev Transfers `_amount` of `wrappedToken` from this contract to `_recipient`.
     * @inheritdoc TokenRouter
     */
    function _transferTo(
        address _recipient,
        uint256 _amount,
        bytes calldata // no metadata
    ) internal virtual override {
        wrappedToken.safeTransfer(_recipient, _amount);
    }
}


// File contracts/token/extensions/FastHypERC20Collateral.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity >=0.8.0;




/**
 * @title Hyperlane ERC20 Token Collateral that wraps an existing ERC20 with remote transfer functionality.
 * @author Abacus Works
 */
contract FastHypERC20Collateral is FastTokenRouter, HypERC20Collateral {
    using SafeERC20 for IERC20;

    /**
     * @notice Constructor
     * @param erc20 Address of the token to keep as collateral
     */
    constructor(
        address erc20,
        address _mailbox
    ) HypERC20Collateral(erc20, _mailbox) {}

    /**
     * @dev delegates transfer logic to `_transferTo`.
     * @inheritdoc FastTokenRouter
     */
    function _handle(
        uint32 _origin,
        bytes32 _sender,
        bytes calldata _message
    ) internal virtual override(FastTokenRouter, TokenRouter) {
        FastTokenRouter._handle(_origin, _sender, _message);
    }

    /**
     * @dev Transfers `_amount` of `wrappedToken` to `_recipient`.
     * @inheritdoc FastTokenRouter
     */
    function _fastTransferTo(
        address _recipient,
        uint256 _amount
    ) internal override {
        wrappedToken.safeTransfer(_recipient, _amount);
    }

    /**
     * @dev Transfers in `_amount` of `wrappedToken` from `_recipient`.
     * @inheritdoc FastTokenRouter
     */
    function _fastRecieveFrom(
        address _sender,
        uint256 _amount
    ) internal override {
        wrappedToken.safeTransferFrom(_sender, address(this), _amount);
    }
}


// File contracts/token/HypERC721Collateral.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity >=0.8.0;


/**
 * @title Hyperlane ERC721 Token Collateral that wraps an existing ERC721 with remote transfer functionality.
 * @author Abacus Works
 */
contract HypERC721Collateral is TokenRouter {
    IERC721 public immutable wrappedToken;

    /**
     * @notice Constructor
     * @param erc721 Address of the token to keep as collateral
     */
    constructor(address erc721, address _mailbox) TokenRouter(_mailbox) {
        wrappedToken = IERC721(erc721);
    }

    function ownerOf(uint256 _tokenId) external view returns (address) {
        return IERC721(wrappedToken).ownerOf(_tokenId);
    }

    /**
     * @dev Returns the balance of `_account` for `wrappedToken`.
     * @inheritdoc TokenRouter
     */
    function balanceOf(
        address _account
    ) external view override returns (uint256) {
        return IERC721(wrappedToken).balanceOf(_account);
    }

    /**
     * @dev Transfers `_tokenId` of `wrappedToken` from `msg.sender` to this contract.
     * @inheritdoc TokenRouter
     */
    function _transferFromSender(
        uint256 _tokenId
    ) internal virtual override returns (bytes memory) {
        // safeTransferFrom not used here because recipient is this contract
        wrappedToken.transferFrom(msg.sender, address(this), _tokenId);
        return bytes(""); // no metadata
    }

    /**
     * @dev Transfers `_tokenId` of `wrappedToken` from this contract to `_recipient`.
     * @inheritdoc TokenRouter
     */
    function _transferTo(
        address _recipient,
        uint256 _tokenId,
        bytes calldata // no metadata
    ) internal override {
        wrappedToken.safeTransferFrom(address(this), _recipient, _tokenId);
    }
}


// File contracts/token/extensions/HypERC721URICollateral.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity >=0.8.0;

/**
 * @title Hyperlane ERC721 Token Collateral that wraps an existing ERC721 with remote transfer and URI relay functionality.
 * @author Abacus Works
 */
contract HypERC721URICollateral is HypERC721Collateral {
    // solhint-disable-next-line no-empty-blocks
    constructor(
        address erc721,
        address _mailbox
    ) HypERC721Collateral(erc721, _mailbox) {}

    /**
     * @dev Transfers `_tokenId` of `wrappedToken` from `msg.sender` to this contract.
     * @return The URI of `_tokenId` on `wrappedToken`.
     * @inheritdoc HypERC721Collateral
     */
    function _transferFromSender(
        uint256 _tokenId
    ) internal override returns (bytes memory) {
        HypERC721Collateral._transferFromSender(_tokenId);
        return
            bytes(
                IERC721MetadataUpgradeable(address(wrappedToken)).tokenURI(
                    _tokenId
                )
            );
    }
}


// File contracts/token/HypERC721.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity >=0.8.0;



/**
 * @title Hyperlane ERC721 Token Router that extends ERC721 with remote transfer functionality.
 * @author Abacus Works
 */
contract HypERC721 is ERC721EnumerableUpgradeable, TokenRouter {
    constructor(address _mailbox) TokenRouter(_mailbox) {}

    /**
     * @notice Initializes the Hyperlane router, ERC721 metadata, and mints initial supply to deployer.
     * @param _mintAmount The amount of NFTs to mint to `msg.sender`.
     * @param _name The name of the token.
     * @param _symbol The symbol of the token.
     */
    function initialize(
        uint256 _mintAmount,
        string memory _name,
        string memory _symbol
    ) external initializer {
        address owner = msg.sender;
        _transferOwnership(owner);

        __ERC721_init(_name, _symbol);
        for (uint256 i = 0; i < _mintAmount; i++) {
            _safeMint(owner, i);
        }
    }

    function balanceOf(
        address _account
    )
        public
        view
        virtual
        override(TokenRouter, ERC721Upgradeable, IERC721Upgradeable)
        returns (uint256)
    {
        return ERC721Upgradeable.balanceOf(_account);
    }

    /**
     * @dev Asserts `msg.sender` is owner and burns `_tokenId`.
     * @inheritdoc TokenRouter
     */
    function _transferFromSender(
        uint256 _tokenId
    ) internal virtual override returns (bytes memory) {
        require(ownerOf(_tokenId) == msg.sender, "!owner");
        _burn(_tokenId);
        return bytes(""); // no metadata
    }

    /**
     * @dev Mints `_tokenId` to `_recipient`.
     * @inheritdoc TokenRouter
     */
    function _transferTo(
        address _recipient,
        uint256 _tokenId,
        bytes calldata // no metadata
    ) internal virtual override {
        _safeMint(_recipient, _tokenId);
    }
}


// File contracts/token/extensions/HypERC721URIStorage.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity >=0.8.0;




/**
 * @title Hyperlane ERC721 Token that extends ERC721URIStorage with remote transfer and URI relay functionality.
 * @author Abacus Works
 */
contract HypERC721URIStorage is HypERC721, ERC721URIStorageUpgradeable {
    constructor(address _mailbox) HypERC721(_mailbox) {}

    function balanceOf(
        address account
    )
        public
        view
        override(HypERC721, ERC721Upgradeable, IERC721Upgradeable)
        returns (uint256)
    {
        return HypERC721.balanceOf(account);
    }

    /**
     * @return _tokenURI The URI of `_tokenId`.
     * @inheritdoc HypERC721
     */
    function _transferFromSender(
        uint256 _tokenId
    ) internal override returns (bytes memory _tokenURI) {
        _tokenURI = bytes(tokenURI(_tokenId)); // requires minted
        HypERC721._transferFromSender(_tokenId);
    }

    /**
     * @dev Sets the URI for `_tokenId` to `_tokenURI`.
     * @inheritdoc HypERC721
     */
    function _transferTo(
        address _recipient,
        uint256 _tokenId,
        bytes calldata _tokenURI
    ) internal override {
        HypERC721._transferTo(_recipient, _tokenId, _tokenURI);
        _setTokenURI(_tokenId, string(_tokenURI)); // requires minted
    }

    function tokenURI(
        uint256 tokenId
    )
        public
        view
        override(ERC721Upgradeable, ERC721URIStorageUpgradeable)
        returns (string memory)
    {
        return ERC721URIStorageUpgradeable.tokenURI(tokenId);
    }

    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 tokenId,
        uint256 batchSize
    ) internal override(ERC721EnumerableUpgradeable, ERC721Upgradeable) {
        ERC721EnumerableUpgradeable._beforeTokenTransfer(
            from,
            to,
            tokenId,
            batchSize
        );
    }

    function supportsInterface(
        bytes4 interfaceId
    )
        public
        view
        override(ERC721EnumerableUpgradeable, ERC721URIStorageUpgradeable)
        returns (bool)
    {
        return ERC721EnumerableUpgradeable.supportsInterface(interfaceId);
    }

    function _burn(
        uint256 tokenId
    ) internal override(ERC721URIStorageUpgradeable, ERC721Upgradeable) {
        ERC721URIStorageUpgradeable._burn(tokenId);
    }
}


// File contracts/token/HypNative.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity >=0.8.0;



/**
 * @title Hyperlane Native Token Router that extends ERC20 with remote transfer functionality.
 * @author Abacus Works
 * @dev Supply on each chain is not constant but the aggregate supply across all chains is.
 */
contract HypNative is TokenRouter {
    /**
     * @dev Emitted when native tokens are donated to the contract.
     * @param sender The address of the sender.
     * @param amount The amount of native tokens donated.
     */
    event Donation(address indexed sender, uint256 amount);

    constructor(address _mailbox) TokenRouter(_mailbox) {}

    /**
     * @inheritdoc TokenRouter
     * @dev uses (`msg.value` - `_amount`) as interchain gas payment and `msg.sender` as refund address.
     */
    function transferRemote(
        uint32 _destination,
        bytes32 _recipient,
        uint256 _amount
    ) public payable virtual override returns (bytes32 messageId) {
        require(msg.value >= _amount, "Native: amount exceeds msg.value");
        uint256 gasPayment = msg.value - _amount;
        return _transferRemote(_destination, _recipient, _amount, gasPayment);
    }

    function balanceOf(
        address _account
    ) external view override returns (uint256) {
        return _account.balance;
    }

    /**
     * @inheritdoc TokenRouter
     * @dev No-op because native amount is transferred in `msg.value`
     * @dev Compiler will not include this in the bytecode.
     */
    function _transferFromSender(
        uint256
    ) internal pure override returns (bytes memory) {
        return bytes(""); // no metadata
    }

    /**
     * @dev Sends `_amount` of native token to `_recipient` balance.
     * @inheritdoc TokenRouter
     */
    function _transferTo(
        address _recipient,
        uint256 _amount,
        bytes calldata // no metadata
    ) internal virtual override {
        Address.sendValue(payable(_recipient), _amount);
    }

    receive() external payable {
        emit Donation(msg.sender, msg.value);
    }
}


// File contracts/token/extensions/HypNativeScaled.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity >=0.8.0;


/**
 * @title Hyperlane Native Token that scales native value by a fixed factor for consistency with other tokens.
 * @dev The scale factor multiplies the `message.amount` to the local native token amount.
 *      Conversely, it divides the local native `msg.value` amount by `scale` to encode the `message.amount`.
 * @author Abacus Works
 */
contract HypNativeScaled is HypNative {
    uint256 public immutable scale;

    constructor(uint256 _scale, address _mailbox) HypNative(_mailbox) {
        scale = _scale;
    }

    /**
     * @inheritdoc HypNative
     * @dev Sends scaled `msg.value` (divided by `scale`) to `_recipient`.
     */
    function transferRemote(
        uint32 _destination,
        bytes32 _recipient,
        uint256 _amount
    ) public payable override returns (bytes32 messageId) {
        require(msg.value >= _amount, "Native: amount exceeds msg.value");
        uint256 gasPayment = msg.value - _amount;
        uint256 scaledAmount = _amount / scale;
        return
            _transferRemote(_destination, _recipient, scaledAmount, gasPayment);
    }

    /**
     * @dev Sends scaled `_amount` (multipled by `scale`) to `_recipient`.
     * @inheritdoc TokenRouter
     */
    function _transferTo(
        address _recipient,
        uint256 _amount,
        bytes calldata metadata // no metadata
    ) internal override {
        uint256 scaledAmount = _amount * scale;
        HypNative._transferTo(_recipient, scaledAmount, metadata);
    }
}


// File contracts/upgrade/ProxyAdmin.sol

// Original license: SPDX_License_Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/transparent/ProxyAdmin.sol)

pragma solidity ^0.8.0;


// File contracts/upgrade/TimelockController.sol

// Original license: SPDX_License_Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (governance/TimelockController.sol)

pragma solidity ^0.8.0;


// File contracts/upgrade/TransparentUpgradeableProxy.sol

// Original license: SPDX_License_Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/transparent/TransparentUpgradeableProxy.sol)

pragma solidity ^0.8.0;


// File contracts/interfaces/IRouter.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity >=0.8.0;

interface IRouter {
    function domains() external view returns (uint32[] memory);

    function routers(uint32 _domain) external view returns (bytes32);

    function enrollRemoteRouter(uint32 _domain, bytes32 _router) external;

    function enrollRemoteRouters(
        uint32[] calldata _domains,
        bytes32[] calldata _routers
    ) external;
}
pragma solidity ^0.8.13;

// ============ External Imports ============

/*
 * @title The Hello World App
 * @dev You can use this simple app as a starting point for your own application.
 */
contract HelloWorld is Router {
    // A generous upper bound on the amount of gas to use in the handle
    // function when a message is processed. Used for paying for gas.
    uint256 public constant HANDLE_GAS_AMOUNT = 50_000;

    // A counter of how many messages have been sent from this contract.
    uint256 public sent;
    // A counter of how many messages have been received by this contract.
    uint256 public received;

    // Keyed by domain, a counter of how many messages that have been sent
    // from this contract to the domain.
    mapping(uint32 => uint256) public sentTo;
    // Keyed by domain, a counter of how many messages that have been received
    // by this contract from the domain.
    mapping(uint32 => uint256) public receivedFrom;

    // ============ Events ============
    event SentHelloWorld(
        uint32 indexed origin,
        uint32 indexed destination,
        string message
    );
    event ReceivedHelloWorld(
        uint32 indexed origin,
        uint32 indexed destination,
        bytes32 sender,
        string message
    );
    event HandleGasAmountSet(
        uint32 indexed destination,
        uint256 handleGasAmount
    );

    constructor(address _mailbox, address _hook) Router(_mailbox) {
        // Transfer ownership of the contract to deployer
        _transferOwnership(msg.sender);
        setHook(_hook);
    }

    // ============ External functions ============

    /**
     * @notice Sends a message to the _destinationDomain. Any msg.value is
     * used as interchain gas payment.
     * @param _destinationDomain The destination domain to send the message to.
     * @param _message The message to send.
     */
    function sendHelloWorld(
        uint32 _destinationDomain,
        string calldata _message
    ) external payable {
        sent += 1;
        sentTo[_destinationDomain] += 1;
        _dispatch(_destinationDomain, bytes(_message));
        emit SentHelloWorld(
            mailbox.localDomain(),
            _destinationDomain,
            _message
        );
    }

    /**
     * @notice Fetches the amount of gas that will be used when a message is
     * dispatched to the given domain.
     */
    function quoteDispatch(
        uint32 _destinationDomain,
        bytes calldata _message
    ) external view returns (uint256) {
        return _quoteDispatch(_destinationDomain, _message);
    }

    // ============ Internal functions ============
    function _metadata(
        uint32 /*_destinationDomain*/
    ) internal view override returns (bytes memory) {
        return StandardHookMetadata.overrideGasLimit(HANDLE_GAS_AMOUNT);
    }

    /**
     * @notice Handles a message from a remote router.
     * @dev Only called for messages sent from a remote router, as enforced by Router.sol.
     * @param _origin The domain of the origin of the message.
     * @param _sender The sender of the message.
     * @param _message The message body.
     */
    function _handle(
        uint32 _origin,
        bytes32 _sender,
        bytes calldata _message
    ) internal override {
        received += 1;
        receivedFrom[_origin] += 1;
        emit ReceivedHelloWorld(
            _origin,
            mailbox.localDomain(),
            _sender,
            string(_message)
        );
    }
}


exec
/bin/bash -lc "rg -n '"'^contract InterchainGasPaymaster|''^contract StorageGasOracle|''^contract Mailbox|''^contract InterchainAccountRouter|''^contract InterchainQueryRouter|''^abstract contract TokenRouter|''^abstract contract FastTokenRouter|''^contract HypERC20|''^contract FastHypERC20|''^contract HypERC20Collateral|''^contract FastHypERC20Collateral|''^contract HypERC721Collateral|''^contract HypERC721 |''^contract HypNative|''^contract HypNativeScaled|''^contract PortalAdapter|''^contract LiquidityLayerRouter|''^contract CircleBridgeAdapter|''^contract ValidatorAnnounce|''^abstract contract AbstractMultisigIsm|''^abstract contract AbstractMerkleRootMultisigIsm|''^abstract contract AbstractMessageIdMultisigIsm|''^contract StaticMerkleRootMultisigIsm|''^contract StaticMessageIdMultisigIsm|''^contract DomainRoutingIsm|''^contract DefaultFallbackRoutingIsm|''^contract ERC5164Ism|''^contract OPStackIsm'"' AUDIT_BUNDLE.txt" in /tmp/codex-3gxliacl
 succeeded in 0ms:
10084:contract InterchainGasPaymaster is
10386:contract StorageGasOracle is IGasOracle, Ownable {
11629:abstract contract AbstractMultisigIsm is IMultisigIsm {
11770:contract ERC5164Ism is AbstractMessageIdAuthorizedIsm {
11823:contract OPStackIsm is
12057:abstract contract AbstractMerkleRootMultisigIsm is AbstractMultisigIsm {
12203:abstract contract AbstractMessageIdMultisigIsm is AbstractMultisigIsm {
12276:contract StaticMerkleRootMultisigIsm is
12286:contract StaticMessageIdMultisigIsm is
12293:contract StaticMerkleRootMultisigIsmFactory is
12301:contract StaticMessageIdMultisigIsmFactory is StaticThresholdAddressSetFactory {
12358:contract ValidatorAnnounce is MailboxClient, IValidatorAnnounce {
12596:contract DomainRoutingIsm is AbstractRoutingIsm, OwnableUpgradeable {
12723:contract DefaultFallbackRoutingIsm is DomainRoutingIsm, MailboxClient {
12813:contract DomainRoutingIsmFactory is AbstractDomainRoutingIsmFactory {
13126:contract Mailbox is IMailbox, Indexed, Versioned, OwnableUpgradeable {
13597:contract InterchainAccountRouter is Router {
14223:contract InterchainQueryRouter is Router {
14485:contract CircleBridgeAdapter is ILiquidityLayerAdapter, Router {
14813:contract PortalAdapter is ILiquidityLayerAdapter, Router {
15058:contract LiquidityLayerRouter is Router, ILiquidityLayerRouter {
16297:abstract contract TokenRouter is GasRouter {
16428:contract HypERC20 is ERC20Upgradeable, TokenRouter {
16502:abstract contract FastTokenRouter is TokenRouter {
16712:contract FastHypERC20 is FastTokenRouter, HypERC20 {
16772:contract HypERC20Collateral is TokenRouter {
16828:contract FastHypERC20Collateral is FastTokenRouter, HypERC20Collateral {
16886:contract HypERC721Collateral is TokenRouter {
16983:contract HypERC721 is ERC721EnumerableUpgradeable, TokenRouter {
17150:contract HypNative is TokenRouter {
17221:contract HypNativeScaled is HypNative {

Finished reading the bundle once end-to-end. Now I’m re-reading the security-critical sections that were truncated in the large chunks and tracing exploit paths.
  ✓ Read AUDIT_BUNDLE.txt fully and identify first-party Solidity sources in scope
  → Analyze contracts for exploit paths in requested categories
  • Produce JSON report with concrete findings and locations
exec
/bin/bash -lc "sed -n '10047,10430p' AUDIT_BUNDLE.txt" in /tmp/codex-3gxliacl
 succeeded in 0ms:
// File contracts/hooks/igp/InterchainGasPaymaster.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity >=0.8.0;

/*@@@@@@@       @@@@@@@@@
 @@@@@@@@@       @@@@@@@@@
  @@@@@@@@@       @@@@@@@@@
   @@@@@@@@@       @@@@@@@@@
    @@@@@@@@@@@@@@@@@@@@@@@@@
     @@@@@  HYPERLANE  @@@@@@@
    @@@@@@@@@@@@@@@@@@@@@@@@@
   @@@@@@@@@       @@@@@@@@@
  @@@@@@@@@       @@@@@@@@@
 @@@@@@@@@       @@@@@@@@@
@@@@@@@@@       @@@@@@@@*/

// ============ Internal Imports ============







// ============ External Imports ============



/**
 * @title InterchainGasPaymaster
 * @notice Manages payments on a source chain to cover gas costs of relaying
 * messages to destination chains and includes the gas overhead per destination
 * @dev The intended use of this contract is to store overhead gas amounts for destination
 * domains, e.g. Mailbox and ISM gas usage, such that users of this IGP are only required
 * to specify the gas amount used by their own applications.
 */
contract InterchainGasPaymaster is
    IInterchainGasPaymaster,
    AbstractPostDispatchHook,
    IGasOracle,
    Indexed,
    OwnableUpgradeable
{
    using Address for address payable;
    using Message for bytes;
    using StandardHookMetadata for bytes;
    // ============ Constants ============

    /// @notice The scale of gas oracle token exchange rates.
    uint256 internal constant TOKEN_EXCHANGE_RATE_SCALE = 1e10;
    /// @notice default for user call if metadata not provided
    uint256 internal immutable DEFAULT_GAS_USAGE = 50_000;

    // ============ Public Storage ============

    /// @notice Destination domain => gas oracle and overhead gas amount.
    mapping(uint32 => DomainGasConfig) public destinationGasConfigs;

    /// @notice The benficiary that can receive native tokens paid into this contract.
    address public beneficiary;

    // ============ Events ============

    /**
     * @notice Emitted when the gas oracle for a remote domain is set.
     * @param remoteDomain The remote domain.
     * @param gasOracle The gas oracle.
     * @param gasOverhead The destination gas overhead.
     */
    event DestinationGasConfigSet(
        uint32 remoteDomain,
        address gasOracle,
        uint96 gasOverhead
    );

    /**
     * @notice Emitted when the beneficiary is set.
     * @param beneficiary The new beneficiary.
     */
    event BeneficiarySet(address beneficiary);

    struct DomainGasConfig {
        IGasOracle gasOracle;
        uint96 gasOverhead;
    }

    struct GasParam {
        uint32 remoteDomain;
        DomainGasConfig config;
    }

    // ============ External Functions ============

    /// @inheritdoc IPostDispatchHook
    function hookType() external pure override returns (uint8) {
        return uint8(IPostDispatchHook.Types.INTERCHAIN_GAS_PAYMASTER);
    }

    /**
     * @param _owner The owner of the contract.
     * @param _beneficiary The beneficiary.
     */
    function initialize(
        address _owner,
        address _beneficiary
    ) public initializer {
        __Ownable_init();
        _transferOwnership(_owner);
        _setBeneficiary(_beneficiary);
    }

    /**
     * @notice Transfers the entire native token balance to the beneficiary.
     * @dev The beneficiary must be able to receive native tokens.
     */
    function claim() external {
        // Transfer the entire balance to the beneficiary.
        (bool success, ) = beneficiary.call{value: address(this).balance}("");
        require(success, "IGP: claim failed");
    }

    /**
     * @notice Sets the gas oracles for remote domains specified in the config array.
     * @param _configs An array of configs including the remote domain and gas oracles to set.
     */
    function setDestinationGasConfigs(
        GasParam[] calldata _configs
    ) external onlyOwner {
        uint256 _len = _configs.length;
        for (uint256 i = 0; i < _len; i++) {
            _setDestinationGasConfig(
                _configs[i].remoteDomain,
                _configs[i].config.gasOracle,
                _configs[i].config.gasOverhead
            );
        }
    }

    /**
     * @notice Sets the beneficiary.
     * @param _beneficiary The new beneficiary.
     */
    function setBeneficiary(address _beneficiary) external onlyOwner {
        _setBeneficiary(_beneficiary);
    }

    // ============ Public Functions ============

    /**
     * @notice Deposits msg.value as a payment for the relaying of a message
     * to its destination chain.
     * @dev Overpayment will result in a refund of native tokens to the _refundAddress.
     * Callers should be aware that this may present reentrancy issues.
     * @param _messageId The ID of the message to pay for.
     * @param _destinationDomain The domain of the message's destination chain.
     * @param _gasLimit The amount of destination gas to pay for.
     * @param _refundAddress The address to refund any overpayment to.
     */
    function payForGas(
        bytes32 _messageId,
        uint32 _destinationDomain,
        uint256 _gasLimit,
        address _refundAddress
    ) public payable override {
        uint256 _requiredPayment = quoteGasPayment(
            _destinationDomain,
            _gasLimit
        );
        require(
            msg.value >= _requiredPayment,
            "IGP: insufficient interchain gas payment"
        );
        uint256 _overpayment = msg.value - _requiredPayment;
        if (_overpayment > 0) {
            require(_refundAddress != address(0), "no refund address");
            payable(_refundAddress).sendValue(_overpayment);
        }

        emit GasPayment(
            _messageId,
            _destinationDomain,
            _gasLimit,
            _requiredPayment
        );
    }

    /**
     * @notice Quotes the amount of native tokens to pay for interchain gas.
     * @param _destinationDomain The domain of the message's destination chain.
     * @param _gasLimit The amount of destination gas to pay for.
     * @return The amount of native tokens required to pay for interchain gas.
     */
    function quoteGasPayment(
        uint32 _destinationDomain,
        uint256 _gasLimit
    ) public view virtual override returns (uint256) {
        // Get the gas data for the destination domain.
        (
            uint128 _tokenExchangeRate,
            uint128 _gasPrice
        ) = getExchangeRateAndGasPrice(_destinationDomain);

        // The total cost quoted in destination chain's native token.
        uint256 _destinationGasCost = _gasLimit * uint256(_gasPrice);

        // Convert to the local native token.
        return
            (_destinationGasCost * _tokenExchangeRate) /
            TOKEN_EXCHANGE_RATE_SCALE;
    }

    /**
     * @notice Gets the token exchange rate and gas price from the configured gas oracle
     * for a given destination domain.
     * @param _destinationDomain The destination domain.
     * @return tokenExchangeRate The exchange rate of the remote native token quoted in the local native token.
     * @return gasPrice The gas price on the remote chain.
     */
    function getExchangeRateAndGasPrice(
        uint32 _destinationDomain
    )
        public
        view
        override
        returns (uint128 tokenExchangeRate, uint128 gasPrice)
    {
        IGasOracle _gasOracle = destinationGasConfigs[_destinationDomain]
            .gasOracle;

        require(
            address(_gasOracle) != address(0),
            string.concat(
                "Configured IGP doesn't support domain ",
                Strings.toString(_destinationDomain)
            )
        );

        return _gasOracle.getExchangeRateAndGasPrice(_destinationDomain);
    }

    /**
     * @notice Returns the stored destinationGasOverhead added to the _gasLimit.
     * @dev If there is no stored destinationGasOverhead, 0 is used. This is useful in the case
     *      the ISM deployer wants to subsidize the overhead gas cost. Then, can specify the gas oracle
     *      they want to use with the destination domain, but set the overhead to 0.
     * @param _destinationDomain The domain of the message's destination chain.
     * @param _gasLimit The amount of destination gas to pay for. This is only for application gas usage as
     *      the gas usage for the mailbox and the ISM is already accounted in the DomainGasConfig.gasOverhead
     */
    function destinationGasLimit(
        uint32 _destinationDomain,
        uint256 _gasLimit
    ) public view returns (uint256) {
        return
            uint256(destinationGasConfigs[_destinationDomain].gasOverhead) +
            _gasLimit;
    }

    // ============ Internal Functions ============

    /// @inheritdoc AbstractPostDispatchHook
    function _postDispatch(
        bytes calldata metadata,
        bytes calldata message
    ) internal override {
        payForGas(
            message.id(),
            message.destination(),
            destinationGasLimit(
                message.destination(),
                metadata.gasLimit(DEFAULT_GAS_USAGE)
            ),
            metadata.refundAddress(message.senderAddress())
        );
    }

    /// @inheritdoc AbstractPostDispatchHook
    function _quoteDispatch(
        bytes calldata metadata,
        bytes calldata message
    ) internal view override returns (uint256) {
        return
            quoteGasPayment(
                message.destination(),
                destinationGasLimit(
                    message.destination(),
                    metadata.gasLimit(DEFAULT_GAS_USAGE)
                )
            );
    }

    /**
     * @notice Sets the beneficiary.
     * @param _beneficiary The new beneficiary.
     */
    function _setBeneficiary(address _beneficiary) internal {
        beneficiary = _beneficiary;
        emit BeneficiarySet(_beneficiary);
    }

    /**
     * @notice Sets the gas oracle and destination gas overhead for a remote domain.
     * @param _remoteDomain The remote domain.
     * @param _gasOracle The gas oracle.
     * @param _gasOverhead The destination gas overhead.
     */
    function _setDestinationGasConfig(
        uint32 _remoteDomain,
        IGasOracle _gasOracle,
        uint96 _gasOverhead
    ) internal {
        destinationGasConfigs[_remoteDomain] = DomainGasConfig(
            _gasOracle,
            _gasOverhead
        );
        emit DestinationGasConfigSet(
            _remoteDomain,
            address(_gasOracle),
            _gasOverhead
        );
    }
}


// File contracts/hooks/igp/StorageGasOracle.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity >=0.8.0;

// ============ Internal Imports ============

// ============ External Imports ============

/**
 * @notice A gas oracle that uses data stored within the contract.
 * @dev This contract is intended to be owned by an address that will
 * update the stored remote gas data.
 */
contract StorageGasOracle is IGasOracle, Ownable {
    // ============ Public Storage ============

    /// @notice Keyed by remote domain, gas data on that remote domain.
    mapping(uint32 => IGasOracle.RemoteGasData) public remoteGasData;

    // ============ Events ============

    /**
     * @notice Emitted when an entry in `remoteGasData` is set.
     * @param remoteDomain The remote domain in which the gas data was set for.
     * @param tokenExchangeRate The exchange rate of the remote native token quoted in the local native token.
     * @param gasPrice The gas price on the remote chain.
     */
    event RemoteGasDataSet(
        uint32 indexed remoteDomain,
        uint128 tokenExchangeRate,
        uint128 gasPrice
    );

    struct RemoteGasDataConfig {
        uint32 remoteDomain;
        uint128 tokenExchangeRate;
        uint128 gasPrice;
    }

    // ============ External Functions ============

    /**
     * @notice Returns the stored `remoteGasData` for the `_destinationDomain`.
     * @param _destinationDomain The destination domain.
     * @return tokenExchangeRate The exchange rate of the remote native token quoted in the local native token.
     * @return gasPrice The gas price on the remote chain.
     */
    function getExchangeRateAndGasPrice(
        uint32 _destinationDomain
    )
        external
        view
        override
        returns (uint128 tokenExchangeRate, uint128 gasPrice)
    {
        // Intentionally allow unset / zero values
        IGasOracle.RemoteGasData memory _data = remoteGasData[
            _destinationDomain

exec
/bin/bash -lc "sed -n '11853,12340p' AUDIT_BUNDLE.txt" in /tmp/codex-3gxliacl
 succeeded in 0ms:
// File contracts/isms/libs/MerkleRootMultisigIsmMetadata.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity >=0.8.0;

/**
 * Format of metadata:
 * [   0:  32] Origin merkle tree address
 * [  32:  36] Index of message ID in merkle tree
 * [  36:  68] Signed checkpoint message ID
 * [  68:1092] Merkle proof
 * [1092:1096] Signed checkpoint index (computed from proof and index)
 * [1096:????] Validator signatures (length := threshold * 65)
 */
library MerkleRootMultisigIsmMetadata {
    uint8 private constant ORIGIN_MERKLE_TREE_OFFSET = 0;
    uint8 private constant MESSAGE_INDEX_OFFSET = 32;
    uint8 private constant MESSAGE_ID_OFFSET = 36;
    uint8 private constant MERKLE_PROOF_OFFSET = 68;
    uint16 private constant MERKLE_PROOF_LENGTH = 32 * 32;
    uint16 private constant SIGNED_INDEX_OFFSET = 1092;
    uint16 private constant SIGNATURES_OFFSET = 1096;
    uint8 private constant SIGNATURE_LENGTH = 65;

    /**
     * @notice Returns the origin merkle tree hook of the signed checkpoint as bytes32.
     * @param _metadata ABI encoded Multisig ISM metadata.
     * @return Origin merkle tree hook of the signed checkpoint as bytes32
     */
    function originMerkleTreeHook(
        bytes calldata _metadata
    ) internal pure returns (bytes32) {
        return
            bytes32(
                _metadata[ORIGIN_MERKLE_TREE_OFFSET:ORIGIN_MERKLE_TREE_OFFSET +
                    32]
            );
    }

    /**
     * @notice Returns the index of the message being proven.
     * @param _metadata ABI encoded Multisig ISM metadata.
     * @return Index of the target message in the merkle tree.
     */
    function messageIndex(
        bytes calldata _metadata
    ) internal pure returns (uint32) {
        return
            uint32(
                bytes4(_metadata[MESSAGE_INDEX_OFFSET:MESSAGE_INDEX_OFFSET + 4])
            );
    }

    /**
     * @notice Returns the index of the signed checkpoint.
     * @param _metadata ABI encoded Multisig ISM metadata.
     * @return Index of the signed checkpoint
     */
    function signedIndex(
        bytes calldata _metadata
    ) internal pure returns (uint32) {
        return
            uint32(
                bytes4(_metadata[SIGNED_INDEX_OFFSET:SIGNED_INDEX_OFFSET + 4])
            );
    }

    /**
     * @notice Returns the message ID of the signed checkpoint.
     * @param _metadata ABI encoded Multisig ISM metadata.
     * @return Message ID of the signed checkpoint
     */
    function signedMessageId(
        bytes calldata _metadata
    ) internal pure returns (bytes32) {
        return bytes32(_metadata[MESSAGE_ID_OFFSET:MESSAGE_ID_OFFSET + 32]);
    }

    /**
     * @notice Returns the merkle proof branch of the message.
     * @dev This appears to be more gas efficient than returning a calldata
     * slice and using that.
     * @param _metadata ABI encoded Multisig ISM metadata.
     * @return Merkle proof branch of the message.
     */
    function proof(
        bytes calldata _metadata
    ) internal pure returns (bytes32[32] memory) {
        return
            abi.decode(
                _metadata[MERKLE_PROOF_OFFSET:MERKLE_PROOF_OFFSET +
                    MERKLE_PROOF_LENGTH],
                (bytes32[32])
            );
    }

    /**
     * @notice Returns the validator ECDSA signature at `_index`.
     * @dev Assumes signatures are sorted by validator
     * @dev Assumes `_metadata` encodes `threshold` signatures.
     * @dev Assumes `_index` is less than `threshold`
     * @param _metadata ABI encoded Multisig ISM metadata.
     * @param _index The index of the signature to return.
     * @return The validator ECDSA signature at `_index`.
     */
    function signatureAt(
        bytes calldata _metadata,
        uint256 _index
    ) internal pure returns (bytes calldata) {
        uint256 _start = SIGNATURES_OFFSET + (_index * SIGNATURE_LENGTH);
        uint256 _end = _start + SIGNATURE_LENGTH;
        return _metadata[_start:_end];
    }
}


// File contracts/libs/CheckpointLib.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity >=0.8.0;

// ============ External Imports ============

library CheckpointLib {
    /**
     * @notice Returns the digest validators are expected to sign when signing checkpoints.
     * @param _origin The origin domain of the checkpoint.
     * @param _originmerkleTreeHook The address of the origin merkle tree hook as bytes32.
     * @param _checkpointRoot The root of the checkpoint.
     * @param _checkpointIndex The index of the checkpoint.
     * @param _messageId The message ID of the checkpoint.
     * @dev Message ID must match leaf content of checkpoint root at index.
     * @return The digest of the checkpoint.
     */
    function digest(
        uint32 _origin,
        bytes32 _originmerkleTreeHook,
        bytes32 _checkpointRoot,
        uint32 _checkpointIndex,
        bytes32 _messageId
    ) internal pure returns (bytes32) {
        bytes32 _domainHash = domainHash(_origin, _originmerkleTreeHook);
        return
            ECDSA.toEthSignedMessageHash(
                keccak256(
                    abi.encodePacked(
                        _domainHash,
                        _checkpointRoot,
                        _checkpointIndex,
                        _messageId
                    )
                )
            );
    }

    /**
     * @notice Returns the domain hash that validators are expected to use
     * when signing checkpoints.
     * @param _origin The origin domain of the checkpoint.
     * @param _originmerkleTreeHook The address of the origin merkle tree as bytes32.
     * @return The domain hash.
     */
    function domainHash(
        uint32 _origin,
        bytes32 _originmerkleTreeHook
    ) internal pure returns (bytes32) {
        // Including the origin merkle tree address in the signature allows the slashing
        // protocol to enroll multiple trees. Otherwise, a valid signature for
        // tree A would be indistinguishable from a fraudulent signature for tree B.
        // The slashing protocol should slash if validators sign attestations for
        // anything other than a whitelisted tree.
        return
            keccak256(
                abi.encodePacked(_origin, _originmerkleTreeHook, "HYPERLANE")
            );
    }
}


// File contracts/isms/multisig/AbstractMerkleRootMultisigIsm.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity >=0.8.0;

// ============ Internal Imports ============






/**
 * @title `AbstractMerkleRootMultisigIsm` — multi-sig ISM with the validators-censorship resistance guarantee.
 * @notice This ISM allows using a newer signed checkpoint (say #33) to prove existence of an older message (#22) in the validators' MerkleTree.
 * This guarantees censorship resistance as validators cannot hide a message
 * by refusing to sign its checkpoint but later signing a checkpoint for a newer message.
 * If validators decide to censor a message, they are left with only one option — to not produce checkpoints at all.
 * Otherwise, the very next signed checkpoint (#33) can be used by any relayer to prove the previous message inclusion using this ISM.
 * This is censorship resistance is missing in the sibling implementation `AbstractMessageIdMultisigIsm`,
 * since it can only verify messages having the corresponding checkpoints.
 * @dev Provides the default implementation of verifying signatures over a checkpoint and the message inclusion in that checkpoint.
 * This abstract contract can be overridden for customizing the `validatorsAndThreshold()` (static or dynamic).
 * @dev May be adapted in future to support batch message verification against a single root.
 */
abstract contract AbstractMerkleRootMultisigIsm is AbstractMultisigIsm {
    using MerkleRootMultisigIsmMetadata for bytes;
    using Message for bytes;

    // ============ Constants ============

    // solhint-disable-next-line const-name-snakecase
    uint8 public constant moduleType =
        uint8(IInterchainSecurityModule.Types.MERKLE_ROOT_MULTISIG);

    /**
     * @inheritdoc AbstractMultisigIsm
     */
    function digest(
        bytes calldata _metadata,
        bytes calldata _message
    ) internal pure override returns (bytes32) {
        require(
            _metadata.messageIndex() <= _metadata.signedIndex(),
            "Invalid merkle index metadata"
        );
        // We verify a merkle proof of (messageId, index) I to compute root J
        bytes32 _signedRoot = MerkleLib.branchRoot(
            _message.id(),
            _metadata.proof(),
            _metadata.messageIndex()
        );
        // We provide (messageId, index) J in metadata for digest derivation
        return
            CheckpointLib.digest(
                _message.origin(),
                _metadata.originMerkleTreeHook(),
                _signedRoot,
                _metadata.signedIndex(),
                _metadata.signedMessageId()
            );
    }

    /**
     * @inheritdoc AbstractMultisigIsm
     */
    function signatureAt(
        bytes calldata _metadata,
        uint256 _index
    ) internal pure virtual override returns (bytes calldata) {
        return _metadata.signatureAt(_index);
    }
}


// File contracts/isms/libs/MessageIdMultisigIsmMetadata.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity >=0.8.0;

/**
 * Format of metadata:
 * [   0:  32] Origin merkle tree address
 * [  32:  64] Signed checkpoint root
 * [  64:  68] Signed checkpoint index
 * [  68:????] Validator signatures (length := threshold * 65)
 */
library MessageIdMultisigIsmMetadata {
    uint8 private constant ORIGIN_MERKLE_TREE_OFFSET = 0;
    uint8 private constant MERKLE_ROOT_OFFSET = 32;
    uint8 private constant MERKLE_INDEX_OFFSET = 64;
    uint8 private constant SIGNATURES_OFFSET = 68;
    uint8 private constant SIGNATURE_LENGTH = 65;

    /**
     * @notice Returns the origin merkle tree hook of the signed checkpoint as bytes32.
     * @param _metadata ABI encoded Multisig ISM metadata.
     * @return Origin merkle tree hook of the signed checkpoint as bytes32
     */
    function originMerkleTreeHook(
        bytes calldata _metadata
    ) internal pure returns (bytes32) {
        return
            bytes32(
                _metadata[ORIGIN_MERKLE_TREE_OFFSET:ORIGIN_MERKLE_TREE_OFFSET +
                    32]
            );
    }

    /**
     * @notice Returns the merkle root of the signed checkpoint.
     * @param _metadata ABI encoded Multisig ISM metadata.
     * @return Merkle root of the signed checkpoint
     */
    function root(bytes calldata _metadata) internal pure returns (bytes32) {
        return bytes32(_metadata[MERKLE_ROOT_OFFSET:MERKLE_ROOT_OFFSET + 32]);
    }

    /**
     * @notice Returns the merkle index of the signed checkpoint.
     * @param _metadata ABI encoded Multisig ISM metadata.
     * @return Merkle index of the signed checkpoint
     */
    function index(bytes calldata _metadata) internal pure returns (uint32) {
        return
            uint32(
                bytes4(_metadata[MERKLE_INDEX_OFFSET:MERKLE_INDEX_OFFSET + 4])
            );
    }

    /**
     * @notice Returns the validator ECDSA signature at `_index`.
     * @dev Assumes signatures are sorted by validator
     * @dev Assumes `_metadata` encodes `threshold` signatures.
     * @dev Assumes `_index` is less than `threshold`
     * @param _metadata ABI encoded Multisig ISM metadata.
     * @param _index The index of the signature to return.
     * @return The validator ECDSA signature at `_index`.
     */
    function signatureAt(
        bytes calldata _metadata,
        uint256 _index
    ) internal pure returns (bytes calldata) {
        uint256 _start = SIGNATURES_OFFSET + (_index * SIGNATURE_LENGTH);
        uint256 _end = _start + SIGNATURE_LENGTH;
        return _metadata[_start:_end];
    }
}


// File contracts/isms/multisig/AbstractMessageIdMultisigIsm.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity >=0.8.0;

// ============ Internal Imports ============





/**
 * @title `AbstractMessageIdMultisigIsm` — multi-sig ISM for the censorship-friendly validators.
 * @notice This ISM minimizes gas/performance overhead of the checkpoints verification by compromising on the censorship resistance.
 * For censorship resistance consider using `AbstractMerkleRootMultisigIsm`.
 * If the validators (`validatorsAndThreshold`) skip messages by not sign checkpoints for them,
 * the relayers will not be able to aggregate a quorum of signatures sufficient to deliver these messages via this ISM.
 * Integrations are free to choose the trade-off between the censorship resistance and the gas/processing overhead.
 * @dev Provides the default implementation of verifying signatures over a checkpoint related to a specific message ID.
 * This abstract contract can be customized to change the `validatorsAndThreshold()` (static or dynamic).
 */
abstract contract AbstractMessageIdMultisigIsm is AbstractMultisigIsm {
    using Message for bytes;
    using MessageIdMultisigIsmMetadata for bytes;

    // ============ Constants ============

    // solhint-disable-next-line const-name-snakecase
    uint8 public constant moduleType =
        uint8(IInterchainSecurityModule.Types.MESSAGE_ID_MULTISIG);

    /**
     * @inheritdoc AbstractMultisigIsm
     */
    function digest(
        bytes calldata _metadata,
        bytes calldata _message
    ) internal pure override returns (bytes32) {
        return
            CheckpointLib.digest(
                _message.origin(),
                _metadata.originMerkleTreeHook(),
                _metadata.root(),
                _metadata.index(),
                _message.id()
            );
    }

    /**
     * @inheritdoc AbstractMultisigIsm
     */
    function signatureAt(
        bytes calldata _metadata,
        uint256 _index
    ) internal pure virtual override returns (bytes calldata) {
        return _metadata.signatureAt(_index);
    }
}


// File contracts/isms/multisig/StaticMultisigIsm.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity >=0.8.0;
// ============ Internal Imports ============





/**
 * @title AbstractMetaProxyMultisigIsm
 * @notice Manages per-domain m-of-n Validator set that is used
 * to verify interchain messages.
 */
abstract contract AbstractMetaProxyMultisigIsm is AbstractMultisigIsm {
    /**
     * @inheritdoc AbstractMultisigIsm
     */
    function validatorsAndThreshold(
        bytes calldata
    ) public pure override returns (address[] memory, uint8) {
        return abi.decode(MetaProxy.metadata(), (address[], uint8));
    }
}

// solhint-disable no-empty-blocks

/**
 * @title StaticMerkleRootMultisigIsm
 * @notice Manages per-domain m-of-n validator set that is used
 * to verify interchain messages using a merkle root signature quorum
 * and merkle proof of inclusion.
 */
contract StaticMerkleRootMultisigIsm is
    AbstractMerkleRootMultisigIsm,
    AbstractMetaProxyMultisigIsm
{}

/**
 * @title StaticMessageIdMultisigIsm
 * @notice Manages per-domain m-of-n validator set that is used
 * to verify interchain messages using a message ID signature quorum.
 */
contract StaticMessageIdMultisigIsm is
    AbstractMessageIdMultisigIsm,
    AbstractMetaProxyMultisigIsm
{}

// solhint-enable no-empty-blocks

contract StaticMerkleRootMultisigIsmFactory is
    StaticThresholdAddressSetFactory
{
    function _deployImplementation() internal override returns (address) {
        return address(new StaticMerkleRootMultisigIsm());
    }
}

contract StaticMessageIdMultisigIsmFactory is StaticThresholdAddressSetFactory {
    function _deployImplementation() internal override returns (address) {
        return address(new StaticMessageIdMultisigIsm());
    }
}


// File contracts/interfaces/IValidatorAnnounce.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity >=0.6.11;

interface IValidatorAnnounce {
    /// @notice Returns a list of validators that have made announcements
    function getAnnouncedValidators() external view returns (address[] memory);

    /**
     * @notice Returns a list of all announced storage locations for `validators`
     * @param _validators The list of validators to get storage locations for
     * @return A list of announced storage locations
     */
    function getAnnouncedStorageLocations(
        address[] calldata _validators
    ) external view returns (string[][] memory);

    /**
     * @notice Announces a validator signature storage location
     * @param _storageLocation Information encoding the location of signed
     * checkpoints
     * @param _signature The signed validator announcement
     * @return True upon success
     */
    function announce(
        address _validator,
        string calldata _storageLocation,
        bytes calldata _signature
    ) external returns (bool);
}



exec
/bin/bash -lc "sed -n '13576,14360p' AUDIT_BUNDLE.txt" in /tmp/codex-3gxliacl
 succeeded in 0ms:
// File contracts/middleware/InterchainAccountRouter.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity ^0.8.13;

// ============ Internal Imports ============







// ============ External Imports ============



/*
 * @title A contract that allows accounts on chain A to call contracts via a
 * proxy contract on chain B.
 */
contract InterchainAccountRouter is Router {
    // ============ Libraries ============

    using TypeCasts for address;
    using TypeCasts for bytes32;

    // ============ Constants ============

    address internal implementation;
    bytes32 internal bytecodeHash;

    // ============ Public Storage ============
    mapping(uint32 => bytes32) public isms;

    // ============ Upgrade Gap ============

    uint256[47] private __GAP;

    // ============ Events ============

    /**
     * @notice Emitted when a default ISM is set for a remote domain
     * @param domain The remote domain
     * @param ism The address of the remote ISM
     */
    event RemoteIsmEnrolled(uint32 indexed domain, bytes32 ism);

    /**
     * @notice Emitted when an interchain call is dispatched to a remote domain
     * @param destination The destination domain on which to make the call
     * @param owner The local owner of the remote ICA
     * @param router The address of the remote router
     * @param ism The address of the remote ISM
     */
    event RemoteCallDispatched(
        uint32 indexed destination,
        address indexed owner,
        bytes32 router,
        bytes32 ism
    );

    /**
     * @notice Emitted when an interchain account contract is deployed
     * @param origin The domain of the chain where the message was sent from
     * @param owner The address of the account that sent the message
     * @param ism The address of the local ISM
     * @param account The address of the proxy account that was created
     */
    event InterchainAccountCreated(
        uint32 indexed origin,
        bytes32 indexed owner,
        address ism,
        address account
    );

    // ============ Constructor ============

    constructor(address _mailbox) Router(_mailbox) {}

    // ============ Initializers ============

    /**
     * @notice Initializes the contract with HyperlaneConnectionClient contracts
     * @param _interchainGasPaymaster Unused but required by HyperlaneConnectionClient
     * @param _interchainSecurityModule The address of the local ISM contract
     * @param _owner The address with owner privileges
     */
    function initialize(
        address _interchainGasPaymaster,
        address _interchainSecurityModule,
        address _owner
    ) external initializer {
        _MailboxClient_initialize(
            _interchainGasPaymaster,
            _interchainSecurityModule,
            _owner
        );

        implementation = address(new OwnableMulticall(address(this)));
        // cannot be stored immutably because it is dynamically sized
        bytes memory _bytecode = MinimalProxy.bytecode(implementation);
        bytecodeHash = keccak256(_bytecode);
    }

    /**
     * @notice Registers the address of remote InterchainAccountRouter
     * and ISM contracts to use as a default when making interchain calls
     * @param _destination The remote domain
     * @param _router The address of the remote InterchainAccountRouter
     * @param _ism The address of the remote ISM
     */
    function enrollRemoteRouterAndIsm(
        uint32 _destination,
        bytes32 _router,
        bytes32 _ism
    ) external onlyOwner {
        _enrollRemoteRouterAndIsm(_destination, _router, _ism);
    }

    /**
     * @notice Registers the address of remote InterchainAccountRouters
     * and ISM contracts to use as defaults when making interchain calls
     * @param _destinations The remote domains
     * @param _routers The address of the remote InterchainAccountRouters
     * @param _isms The address of the remote ISMs
     */
    function enrollRemoteRouterAndIsms(
        uint32[] calldata _destinations,
        bytes32[] calldata _routers,
        bytes32[] calldata _isms
    ) external onlyOwner {
        require(
            _destinations.length == _routers.length &&
                _destinations.length == _isms.length,
            "length mismatch"
        );
        for (uint256 i = 0; i < _destinations.length; i++) {
            _enrollRemoteRouterAndIsm(_destinations[i], _routers[i], _isms[i]);
        }
    }

    // ============ External Functions ============
    /**
     * @notice Dispatches a single remote call to be made by an owner's
     * interchain account on the destination domain
     * @dev Uses the default router and ISM addresses for the destination
     * domain, reverting if none have been configured
     * @param _destination The remote domain of the chain to make calls on
     * @param _to The address of the contract to call
     * @param _value The value to include in the call
     * @param _data The calldata
     * @return The Hyperlane message ID
     */
    function callRemote(
        uint32 _destination,
        address _to,
        uint256 _value,
        bytes memory _data
    ) external returns (bytes32) {
        bytes32 _router = routers(_destination);
        bytes32 _ism = isms[_destination];
        bytes memory _body = InterchainAccountMessage.encode(
            msg.sender,
            _ism,
            _to,
            _value,
            _data
        );
        return _dispatchMessage(_destination, _router, _ism, _body);
    }

    /**
     * @notice Dispatches a sequence of remote calls to be made by an owner's
     * interchain account on the destination domain
     * @dev Uses the default router and ISM addresses for the destination
     * domain, reverting if none have been configured
     * @dev Recommend using CallLib.build to format the interchain calls.
     * @param _destination The remote domain of the chain to make calls on
     * @param _calls The sequence of calls to make
     * @return The Hyperlane message ID
     */
    function callRemote(
        uint32 _destination,
        CallLib.Call[] calldata _calls
    ) external returns (bytes32) {
        bytes32 _router = routers(_destination);
        bytes32 _ism = isms[_destination];
        return callRemoteWithOverrides(_destination, _router, _ism, _calls);
    }

    /**
     * @notice Handles dispatched messages by relaying calls to the interchain account
     * @param _origin The origin domain of the interchain account
     * @param _sender The sender of the interchain message
     * @param _message The InterchainAccountMessage containing the account
     * owner, ISM, and sequence of calls to be relayed
     * @dev Does not need to be onlyRemoteRouter, as this application is designed
     * to receive messages from untrusted remote contracts.
     */
    function handle(
        uint32 _origin,
        bytes32 _sender,
        bytes calldata _message
    ) external payable override onlyMailbox {
        (
            bytes32 _owner,
            bytes32 _ism,
            CallLib.Call[] memory _calls
        ) = InterchainAccountMessage.decode(_message);

        OwnableMulticall _interchainAccount = getDeployedInterchainAccount(
            _origin,
            _owner,
            _sender,
            _ism.bytes32ToAddress()
        );
        _interchainAccount.multicall(_calls);
    }

    /**
     * @notice Returns the local address of an interchain account
     * @dev This interchain account is not guaranteed to have been deployed
     * @param _origin The remote origin domain of the interchain account
     * @param _router The remote origin InterchainAccountRouter
     * @param _owner The remote owner of the interchain account
     * @param _ism The local address of the ISM
     * @return The local address of the interchain account
     */
    function getLocalInterchainAccount(
        uint32 _origin,
        address _owner,
        address _router,
        address _ism
    ) external view returns (OwnableMulticall) {
        return
            getLocalInterchainAccount(
                _origin,
                _owner.addressToBytes32(),
                _router.addressToBytes32(),
                _ism
            );
    }

    /**
     * @notice Returns the remote address of a locally owned interchain account
     * @dev This interchain account is not guaranteed to have been deployed
     * @dev This function will only work if the destination domain is
     * EVM compatible
     * @param _destination The remote destination domain of the interchain account
     * @param _owner The local owner of the interchain account
     * @return The remote address of the interchain account
     */
    function getRemoteInterchainAccount(
        uint32 _destination,
        address _owner
    ) external view returns (address) {
        address _router = routers(_destination).bytes32ToAddress();
        address _ism = isms[_destination].bytes32ToAddress();
        return getRemoteInterchainAccount(_owner, _router, _ism);
    }

    // ============ Public Functions ============

    /**
     * @notice Returns and deploys (if not already) an interchain account
     * @param _origin The remote origin domain of the interchain account
     * @param _owner The remote owner of the interchain account
     * @param _router The remote origin InterchainAccountRouter
     * @param _ism The local address of the ISM
     * @return The address of the interchain account
     */
    function getDeployedInterchainAccount(
        uint32 _origin,
        address _owner,
        address _router,
        address _ism
    ) public returns (OwnableMulticall) {
        return
            getDeployedInterchainAccount(
                _origin,
                _owner.addressToBytes32(),
                _router.addressToBytes32(),
                _ism
            );
    }

    /**
     * @notice Returns and deploys (if not already) an interchain account
     * @param _origin The remote origin domain of the interchain account
     * @param _owner The remote owner of the interchain account
     * @param _router The remote origin InterchainAccountRouter
     * @param _ism The local address of the ISM
     * @return The address of the interchain account
     */
    function getDeployedInterchainAccount(
        uint32 _origin,
        bytes32 _owner,
        bytes32 _router,
        address _ism
    ) public returns (OwnableMulticall) {
        bytes32 _salt = _getSalt(
            _origin,
            _owner,
            _router,
            _ism.addressToBytes32()
        );
        address payable _account = _getLocalInterchainAccount(_salt);
        if (!Address.isContract(_account)) {
            bytes memory _bytecode = MinimalProxy.bytecode(implementation);
            _account = payable(Create2.deploy(0, _salt, _bytecode));
            emit InterchainAccountCreated(_origin, _owner, _ism, _account);
        }
        return OwnableMulticall(_account);
    }

    /**
     * @notice Returns the local address of a remotely owned interchain account
     * @dev This interchain account is not guaranteed to have been deployed
     * @param _origin The remote origin domain of the interchain account
     * @param _owner The remote owner of the interchain account
     * @param _router The remote InterchainAccountRouter
     * @param _ism The local address of the ISM
     * @return The local address of the interchain account
     */
    function getLocalInterchainAccount(
        uint32 _origin,
        bytes32 _owner,
        bytes32 _router,
        address _ism
    ) public view returns (OwnableMulticall) {
        return
            OwnableMulticall(
                _getLocalInterchainAccount(
                    _getSalt(_origin, _owner, _router, _ism.addressToBytes32())
                )
            );
    }

    /**
     * @notice Returns the remote address of a locally owned interchain account
     * @dev This interchain account is not guaranteed to have been deployed
     * @dev This function will only work if the destination domain is
     * EVM compatible
     * @param _owner The local owner of the interchain account
     * @param _router The remote InterchainAccountRouter
     * @param _ism The remote address of the ISM
     * @return The remote address of the interchain account
     */
    function getRemoteInterchainAccount(
        address _owner,
        address _router,
        address _ism
    ) public view returns (address) {
        require(_router != address(0), "no router specified for destination");
        // Derives the address of the first contract deployed by _router using
        // the CREATE opcode.
        address _implementation = address(
            uint160(
                uint256(
                    keccak256(
                        abi.encodePacked(
                            bytes1(0xd6),
                            bytes1(0x94),
                            _router,
                            bytes1(0x01)
                        )
                    )
                )
            )
        );
        bytes memory _proxyBytecode = MinimalProxy.bytecode(_implementation);
        bytes32 _bytecodeHash = keccak256(_proxyBytecode);
        bytes32 _salt = _getSalt(
            localDomain,
            _owner.addressToBytes32(),
            address(this).addressToBytes32(),
            _ism.addressToBytes32()
        );
        return Create2.computeAddress(_salt, _bytecodeHash, _router);
    }

    /**
     * @notice Dispatches a sequence of remote calls to be made by an owner's
     * interchain account on the destination domain
     * @dev Recommend using CallLib.build to format the interchain calls
     * @param _destination The remote domain of the chain to make calls on
     * @param _router The remote router address
     * @param _ism The remote ISM address
     * @param _calls The sequence of calls to make
     * @return The Hyperlane message ID
     */
    function callRemoteWithOverrides(
        uint32 _destination,
        bytes32 _router,
        bytes32 _ism,
        CallLib.Call[] calldata _calls
    ) public returns (bytes32) {
        bytes memory _body = InterchainAccountMessage.encode(
            msg.sender,
            _ism,
            _calls
        );
        return _dispatchMessage(_destination, _router, _ism, _body);
    }

    // ============ Internal Functions ============

    /**
     * @dev Required for use of Router, compiler will not include this function in the bytecode
     */
    function _handle(uint32, bytes32, bytes calldata) internal pure override {
        assert(false);
    }

    /**
     * @notice Overrides Router._enrollRemoteRouter to also enroll a default ISM
     * @param _destination The remote domain
     * @param _address The address of the remote InterchainAccountRouter
     * @dev Sets the default ISM to the zero address
     */
    function _enrollRemoteRouter(
        uint32 _destination,
        bytes32 _address
    ) internal override {
        _enrollRemoteRouterAndIsm(_destination, _address, bytes32(0));
    }

    // ============ Private Functions ============

    /**
     * @notice Registers the address of a remote ISM contract to use as default
     * @param _destination The remote domain
     * @param _ism The address of the remote ISM
     */
    function _enrollRemoteIsm(uint32 _destination, bytes32 _ism) private {
        isms[_destination] = _ism;
        emit RemoteIsmEnrolled(_destination, _ism);
    }

    /**
     * @notice Registers the address of remote InterchainAccountRouter
     * and ISM contracts to use as a default when making interchain calls
     * @param _destination The remote domain
     * @param _router The address of the remote InterchainAccountRouter
     * @param _ism The address of the remote ISM
     */
    function _enrollRemoteRouterAndIsm(
        uint32 _destination,
        bytes32 _router,
        bytes32 _ism
    ) private {
        require(
            routers(_destination) == bytes32(0) &&
                isms[_destination] == bytes32(0),
            "router and ISM defaults are immutable once set"
        );
        Router._enrollRemoteRouter(_destination, _router);
        _enrollRemoteIsm(_destination, _ism);
    }

    /**
     * @notice Dispatches an InterchainAccountMessage to the remote router
     * @param _destination The remote domain
     * @param _router The address of the remote InterchainAccountRouter
     * @param _ism The address of the remote ISM
     * @param _body The InterchainAccountMessage body
     */
    function _dispatchMessage(
        uint32 _destination,
        bytes32 _router,
        bytes32 _ism,
        bytes memory _body
    ) private returns (bytes32) {
        require(_router != bytes32(0), "no router specified for destination");
        emit RemoteCallDispatched(_destination, msg.sender, _router, _ism);
        return mailbox.dispatch(_destination, _router, _body);
    }

    /**
     * @notice Returns the salt used to deploy an interchain account
     * @param _origin The remote origin domain of the interchain account
     * @param _owner The remote owner of the interchain account
     * @param _router The remote origin InterchainAccountRouter
     * @param _ism The local address of the ISM
     * @return The CREATE2 salt used for deploying the interchain account
     */
    function _getSalt(
        uint32 _origin,
        bytes32 _owner,
        bytes32 _router,
        bytes32 _ism
    ) private pure returns (bytes32) {
        return keccak256(abi.encodePacked(_origin, _owner, _router, _ism));
    }

    /**
     * @notice Returns the address of the interchain account on the local chain
     * @param _salt The CREATE2 salt used for deploying the interchain account
     * @return The address of the interchain account
     */
    function _getLocalInterchainAccount(
        bytes32 _salt
    ) private view returns (address payable) {
        return payable(Create2.computeAddress(_salt, bytecodeHash));
    }
}


// File contracts/middleware/libs/InterchainQueryMessage.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity ^0.8.13;

/**
 * Format of message:
 * [   0: 32] Sender address
 * [  32: 64] Message type (left padded with zeroes)
 * [  64:???] Encoded call array
 */
library InterchainQueryMessage {
    uint256 private constant SENDER_OFFSET = 0;
    uint256 private constant TYPE_OFFSET = 32;
    uint256 private constant CALLS_OFFSET = 64;

    enum MessageType {
        QUERY,
        RESPONSE
    }

    /**
     * @notice Parses and returns the query sender from the provided message
     * @param _message The interchain query message
     * @return The query sender as bytes32
     */
    function sender(bytes calldata _message) internal pure returns (bytes32) {
        return bytes32(_message[SENDER_OFFSET:TYPE_OFFSET]);
    }

    /**
     * @notice Parses and returns the message type from the provided message
     * @param _message The interchain query message
     * @return The message type (query or response)
     */
    function messageType(
        bytes calldata _message
    ) internal pure returns (MessageType) {
        // left padded with zeroes
        return MessageType(uint8(bytes1(_message[CALLS_OFFSET - 1])));
    }

    /**
     * @notice Returns formatted InterchainQueryMessage, type == QUERY
     * @param _sender The query sender as bytes32
     * @param _calls The sequence of queries to make, with the corresponding
     * response callbacks
     * @return Formatted message body
     */
    function encode(
        bytes32 _sender,
        CallLib.StaticCallWithCallback[] calldata _calls
    ) internal pure returns (bytes memory) {
        return abi.encode(_sender, MessageType.QUERY, _calls);
    }

    /**
     * @notice Returns formatted InterchainQueryMessage, type == QUERY
     * @param _sender The query sender as bytes32
     * @param _to The address of the contract to query
     * @param _data The calldata encoding the query
     * @param _callback The calldata of the callback that will be made on the sender.
     * The return value of the query will be appended.
     * @return Formatted message body
     */
    function encode(
        bytes32 _sender,
        address _to,
        bytes memory _data,
        bytes memory _callback
    ) internal pure returns (bytes memory) {
        CallLib.StaticCallWithCallback[]
            memory _calls = new CallLib.StaticCallWithCallback[](1);
        _calls[0] = CallLib.build(_to, _data, _callback);
        return abi.encode(_sender, MessageType.QUERY, _calls);
    }

    /**
     * @notice Parses and returns the calls and callbacks from the message
     * @param _message The interchain query message, type == QUERY
     * @return _calls The sequence of queries to make with the corresponding
     * response callbacks
     */
    function callsWithCallbacks(
        bytes calldata _message
    ) internal pure returns (CallLib.StaticCallWithCallback[] memory _calls) {
        assert(messageType(_message) == MessageType.QUERY);
        (, , _calls) = abi.decode(
            _message,
            (bytes32, MessageType, CallLib.StaticCallWithCallback[])
        );
    }

    /**
     * @notice Returns formatted InterchainQueryMessage, type == RESPONSE
     * @param _sender The query sender as bytes32
     * @param _calls The sequence of callbacks to make
     * @return Formatted message body
     */
    function encode(
        bytes32 _sender,
        bytes[] memory _calls
    ) internal pure returns (bytes memory) {
        return abi.encode(_sender, MessageType.RESPONSE, _calls);
    }

    /**
     * @notice Parses and returns the callbacks from the message
     * @param _message The interchain query message, type == RESPONSE
     * @return _calls The sequence of callbacks to make
     */
    function rawCalls(
        bytes calldata _message
    ) internal pure returns (bytes[] memory _calls) {
        assert(messageType(_message) == MessageType.RESPONSE);
        (, , _calls) = abi.decode(_message, (bytes32, MessageType, bytes[]));
    }
}


// File contracts/middleware/InterchainQueryRouter.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity ^0.8.13;

// ============ Internal Imports ============




// ============ External Imports ============



/**
 * @title Interchain Query Router that performs remote view calls on other chains and returns the result.
 * @dev Currently does not support Sovereign Consensus (user specified Interchain Security Modules).
 */
contract InterchainQueryRouter is Router {
    using TypeCasts for address;
    using TypeCasts for bytes32;
    using InterchainQueryMessage for bytes;

    /**
     * @notice Emitted when a query is dispatched to another chain.
     * @param destination The domain of the chain to query.
     * @param sender The address that dispatched the query.
     */
    event QueryDispatched(uint32 indexed destination, address indexed sender);
    /**
     * @notice Emitted when a query is executed on the and callback dispatched to the origin chain.
     * @param originDomain The domain of the chain that dispatched the query and receives the callback.
     * @param sender The address to receive the result.
     */
    event QueryExecuted(uint32 indexed originDomain, bytes32 indexed sender);
    /**
     * @notice Emitted when a query is resolved on the origin chain.
     * @param destination The domain of the chain that was queried.
     * @param sender The address that resolved the query.
     */
    event QueryResolved(uint32 indexed destination, address indexed sender);

    constructor(address _mailbox) Router(_mailbox) {}

    /**
     * @notice Initializes the Router contract with Hyperlane core contracts and the address of the interchain security module.
     * @param _interchainGasPaymaster The address of the interchain gas paymaster contract.
     * @param _interchainSecurityModule The address of the interchain security module contract.
     * @param _owner The address with owner privileges.
     */
    function initialize(
        address _interchainGasPaymaster,
        address _interchainSecurityModule,
        address _owner
    ) external initializer {
        _MailboxClient_initialize(
            _interchainGasPaymaster,
            _interchainSecurityModule,
            _owner
        );
    }

    /**
     * @notice Dispatches a sequence of static calls (query) to the destination domain and set of callbacks to resolve the results on the dispatcher.
     * @param _destination The domain of the chain to query.
     * @param _to The address of the contract to query
     * @param _data The calldata encoding the query
     * @param _callback The calldata of the callback that will be made on the sender.
     * The return value of the query will be appended.
     * @dev Callbacks must be returned to the `msg.sender` for security reasons. Require this contract is the `msg.sender` on callbacks.
     */
    function query(
        uint32 _destination,
        address _to,
        bytes memory _data,
        bytes memory _callback
    ) public returns (bytes32 messageId) {
        emit QueryDispatched(_destination, msg.sender);

        messageId = _dispatch(
            _destination,
            InterchainQueryMessage.encode(
                msg.sender.addressToBytes32(),
                _to,
                _data,
                _callback
            )
        );
    }

    /**
     * @notice Dispatches a sequence of static calls (query) to the destination domain and set of callbacks to resolve the results on the dispatcher.
     * @param _destination The domain of the chain to query.
     * @param calls The sequence of static calls to dispatch and callbacks on the sender to resolve the results.
     * @dev Recommend using CallLib.build to format the interchain calls.
     * @dev Callbacks must be returned to the `msg.sender` for security reasons. Require this contract is the `msg.sender` on callbacks.
     */
    function query(
        uint32 _destination,
        CallLib.StaticCallWithCallback[] calldata calls
    ) public returns (bytes32 messageId) {
        emit QueryDispatched(_destination, msg.sender);
        messageId = _dispatch(
            _destination,
            InterchainQueryMessage.encode(msg.sender.addressToBytes32(), calls)
        );
    }

    /**
     * @notice Handles a message from remote enrolled Interchain Query Router.
     * @param _origin The domain of the chain that sent the message.
     * @param _message The ABI-encoded interchain query.
     */
    function _handle(
        uint32 _origin,
        bytes32, // router sender
        bytes calldata _message
    ) internal override {
        InterchainQueryMessage.MessageType messageType = _message.messageType();
        bytes32 sender = _message.sender();
        if (messageType == InterchainQueryMessage.MessageType.QUERY) {
            CallLib.StaticCallWithCallback[]
                memory callsWithCallback = InterchainQueryMessage
                    .callsWithCallbacks(_message);
            bytes[] memory callbacks = CallLib.multistaticcall(
                callsWithCallback
            );
            emit QueryExecuted(_origin, sender);
            _dispatch(
                _origin,
                InterchainQueryMessage.encode(sender, callbacks)
            );
        } else if (messageType == InterchainQueryMessage.MessageType.RESPONSE) {
            address senderAddress = sender.bytes32ToAddress();
            bytes[] memory rawCalls = _message.rawCalls();
            CallLib.multicallto(senderAddress, rawCalls);
            emit QueryResolved(_origin, senderAddress);
        } else {
            assert(false);
        }
    }
}


// File contracts/middleware/liquidity-layer/interfaces/circle/ICircleMessageTransmitter.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity ^0.8.13;

interface ICircleMessageTransmitter {
    /**
     * @notice Receive a message. Messages with a given nonce
     * can only be broadcast once for a (sourceDomain, destinationDomain)
     * pair. The message body of a valid message is passed to the
     * specified recipient for further processing.
     *

exec
/bin/bash -lc "sed -n '16250,16780p' AUDIT_BUNDLE.txt" in /tmp/codex-3gxliacl
 succeeded in 0ms:
// File contracts/token/libs/TokenMessage.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity >=0.8.0;

library TokenMessage {
    function format(
        bytes32 _recipient,
        uint256 _amount,
        bytes memory _metadata
    ) internal pure returns (bytes memory) {
        return abi.encodePacked(_recipient, _amount, _metadata);
    }

    function recipient(bytes calldata message) internal pure returns (bytes32) {
        return bytes32(message[0:32]);
    }

    function amount(bytes calldata message) internal pure returns (uint256) {
        return uint256(bytes32(message[32:64]));
    }

    // alias for ERC721
    function tokenId(bytes calldata message) internal pure returns (uint256) {
        return amount(message);
    }

    function metadata(
        bytes calldata message
    ) internal pure returns (bytes calldata) {
        return message[64:];
    }
}


// File contracts/token/libs/TokenRouter.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity >=0.8.0;




/**
 * @title Hyperlane Token Router that extends Router with abstract token (ERC20/ERC721) remote transfer functionality.
 * @author Abacus Works
 */
abstract contract TokenRouter is GasRouter {
    using TypeCasts for bytes32;
    using TypeCasts for address;
    using TokenMessage for bytes;

    /**
     * @dev Emitted on `transferRemote` when a transfer message is dispatched.
     * @param destination The identifier of the destination chain.
     * @param recipient The address of the recipient on the destination chain.
     * @param amount The amount of tokens burnt on the origin chain.
     */
    event SentTransferRemote(
        uint32 indexed destination,
        bytes32 indexed recipient,
        uint256 amount
    );

    /**
     * @dev Emitted on `_handle` when a transfer message is processed.
     * @param origin The identifier of the origin chain.
     * @param recipient The address of the recipient on the destination chain.
     * @param amount The amount of tokens minted on the destination chain.
     */
    event ReceivedTransferRemote(
        uint32 indexed origin,
        bytes32 indexed recipient,
        uint256 amount
    );

    constructor(address _mailbox) GasRouter(_mailbox) {}

    /**
     * @notice Transfers `_amountOrId` token to `_recipient` on `_destination` domain.
     * @dev Delegates transfer logic to `_transferFromSender` implementation.
     * @dev Emits `SentTransferRemote` event on the origin chain.
     * @param _destination The identifier of the destination chain.
     * @param _recipient The address of the recipient on the destination chain.
     * @param _amountOrId The amount or identifier of tokens to be sent to the remote recipient.
     * @return messageId The identifier of the dispatched message.
     */
    function transferRemote(
        uint32 _destination,
        bytes32 _recipient,
        uint256 _amountOrId
    ) external payable virtual returns (bytes32 messageId) {
        return
            _transferRemote(_destination, _recipient, _amountOrId, msg.value);
    }

    /**
     * @notice Transfers `_amountOrId` token to `_recipient` on `_destination` domain.
     * @dev Delegates transfer logic to `_transferFromSender` implementation.
     * @dev Emits `SentTransferRemote` event on the origin chain.
     * @param _destination The identifier of the destination chain.
     * @param _recipient The address of the recipient on the destination chain.
     * @param _amountOrId The amount or identifier of tokens to be sent to the remote recipient.
     * @param _gasPayment The amount of native token to pay for interchain gas.
     * @return messageId The identifier of the dispatched message.
     */
    function _transferRemote(
        uint32 _destination,
        bytes32 _recipient,
        uint256 _amountOrId,
        uint256 _gasPayment
    ) internal returns (bytes32 messageId) {
        bytes memory metadata = _transferFromSender(_amountOrId);
        messageId = _dispatch(
            _destination,
            _gasPayment,
            TokenMessage.format(_recipient, _amountOrId, metadata)
        );
        emit SentTransferRemote(_destination, _recipient, _amountOrId);
    }

    /**
     * @dev Should transfer `_amountOrId` of tokens from `msg.sender` to this token router.
     * @dev Called by `transferRemote` before message dispatch.
     * @dev Optionally returns `metadata` associated with the transfer to be passed in message.
     */
    function _transferFromSender(
        uint256 _amountOrId
    ) internal virtual returns (bytes memory metadata);

    /**
     * @notice Returns the balance of `account` on this token router.
     * @param account The address to query the balance of.
     * @return The balance of `account`.
     */
    function balanceOf(address account) external virtual returns (uint256);

    /**
     * @dev Mints tokens to recipient when router receives transfer message.
     * @dev Emits `ReceivedTransferRemote` event on the destination chain.
     * @param _origin The identifier of the origin chain.
     * @param _message The encoded remote transfer message containing the recipient address and amount.
     */
    function _handle(
        uint32 _origin,
        bytes32,
        bytes calldata _message
    ) internal virtual override {
        bytes32 recipient = _message.recipient();
        uint256 amount = _message.amount();
        bytes calldata metadata = _message.metadata();
        _transferTo(recipient.bytes32ToAddress(), amount, metadata);
        emit ReceivedTransferRemote(_origin, recipient, amount);
    }

    /**
     * @dev Should transfer `_amountOrId` of tokens from this token router to `_recipient`.
     * @dev Called by `handle` after message decoding.
     * @dev Optionally handles `metadata` associated with transfer passed in message.
     */
    function _transferTo(
        address _recipient,
        uint256 _amountOrId,
        bytes calldata metadata
    ) internal virtual;
}


// File contracts/token/HypERC20.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity >=0.8.0;

/**
 * @title Hyperlane ERC20 Token Router that extends ERC20 with remote transfer functionality.
 * @author Abacus Works
 * @dev Supply on each chain is not constant but the aggregate supply across all chains is.
 */
contract HypERC20 is ERC20Upgradeable, TokenRouter {
    uint8 private immutable _decimals;

    constructor(uint8 __decimals, address _mailbox) TokenRouter(_mailbox) {
        _decimals = __decimals;
    }

    /**
     * @notice Initializes the Hyperlane router, ERC20 metadata, and mints initial supply to deployer.
     * @param _totalSupply The initial supply of the token.
     * @param _name The name of the token.
     * @param _symbol The symbol of the token.
     */
    function initialize(
        uint256 _totalSupply,
        string memory _name,
        string memory _symbol
    ) external initializer {
        // Initialize ERC20 metadata
        __ERC20_init(_name, _symbol);
        _mint(msg.sender, _totalSupply);
    }

    function decimals() public view override returns (uint8) {
        return _decimals;
    }

    function balanceOf(
        address _account
    )
        public
        view
        virtual
        override(TokenRouter, ERC20Upgradeable)
        returns (uint256)
    {
        return ERC20Upgradeable.balanceOf(_account);
    }

    /**
     * @dev Burns `_amount` of token from `msg.sender` balance.
     * @inheritdoc TokenRouter
     */
    function _transferFromSender(
        uint256 _amount
    ) internal override returns (bytes memory) {
        _burn(msg.sender, _amount);
        return bytes(""); // no metadata
    }

    /**
     * @dev Mints `_amount` of token to `_recipient` balance.
     * @inheritdoc TokenRouter
     */
    function _transferTo(
        address _recipient,
        uint256 _amount,
        bytes calldata // no metadata
    ) internal virtual override {
        _mint(_recipient, _amount);
    }
}


// File contracts/token/libs/FastTokenRouter.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity >=0.8.0;


/**
 * @title Common FastTokenRouter functionality for ERC20 Tokens with remote transfer support.
 * @author Abacus Works
 */
abstract contract FastTokenRouter is TokenRouter {
    using TypeCasts for bytes32;
    using TokenMessage for bytes;

    uint256 public fastTransferId;
    // maps `fastTransferId` to the filler address.
    mapping(bytes32 => address) filledFastTransfers;

    /**
     * @dev delegates transfer logic to `_transferTo`.
     * @inheritdoc TokenRouter
     */
    function _handle(
        uint32 _origin,
        bytes32,
        bytes calldata _message
    ) internal virtual override {
        bytes32 recipient = _message.recipient();
        uint256 amount = _message.amount();
        bytes calldata metadata = _message.metadata();
        _transferTo(recipient.bytes32ToAddress(), amount, _origin, metadata);
        emit ReceivedTransferRemote(_origin, recipient, amount);
    }

    /**
     * @dev Transfers `_amount` of token to `_recipient`/`fastFiller` who provided LP.
     * @dev Called by `handle` after message decoding.
     */
    function _transferTo(
        address _recipient,
        uint256 _amount,
        uint32 _origin,
        bytes calldata _metadata
    ) internal virtual {
        address _tokenRecipient = _getTokenRecipient(
            _recipient,
            _amount,
            _origin,
            _metadata
        );

        _fastTransferTo(_tokenRecipient, _amount);
    }

    /**
     * @dev allows an external user to full an unfilled fast transfer order.
     * @param _recipient The recepient of the wrapped token on base chain.
     * @param _amount The amount of wrapped tokens that is being bridged.
     * @param _fastFee The fee the bridging entity will pay.
     * @param _fastTransferId Id assigned on the remote chain to uniquely identify the transfer.
     */
    function fillFastTransfer(
        address _recipient,
        uint256 _amount,
        uint256 _fastFee,
        uint32 _origin,
        uint256 _fastTransferId
    ) external virtual {
        bytes32 filledFastTransfersKey = _getFastTransfersKey(
            _origin,
            _fastTransferId,
            _amount,
            _fastFee,
            _recipient
        );
        require(
            filledFastTransfers[filledFastTransfersKey] == address(0),
            "request already filled"
        );

        filledFastTransfers[filledFastTransfersKey] = msg.sender;

        _fastRecieveFrom(msg.sender, _amount - _fastFee);
        _fastTransferTo(_recipient, _amount - _fastFee);
    }

    /**
     * @dev Transfers `_amountOrId` token to `_recipient` on `_destination` domain.
     * @dev Delegates transfer logic to `_fastTransferFromSender` implementation.
     * @dev Emits `SentTransferRemote` event on the origin chain.
     * @param _destination The identifier of the destination chain.
     * @param _recipient The address of the recipient on the destination chain.
     * @param _amountOrId The amount or identifier of tokens to be sent to the remote recipient.
     * @return messageId The identifier of the dispatched message.
     */
    function fastTransferRemote(
        uint32 _destination,
        bytes32 _recipient,
        uint256 _amountOrId,
        uint256 _fastFee
    ) public payable virtual returns (bytes32 messageId) {
        uint256 _fastTransferId = fastTransferId + 1;
        fastTransferId = _fastTransferId;
        bytes memory metadata = _fastTransferFromSender(
            _amountOrId,
            _fastFee,
            _fastTransferId
        );

        messageId = _dispatch(
            _destination,
            TokenMessage.format(_recipient, _amountOrId, metadata)
        );
        emit SentTransferRemote(_destination, _recipient, _amountOrId);
    }

    /**
     * @dev Burns `_amount` of token from `msg.sender` balance.
     * @dev Pays `_fastFee` of tokens to LP on source chain.
     * @dev Returns `fastFee` as bytes in the form of metadata.
     */
    function _fastTransferFromSender(
        uint256 _amount,
        uint256 _fastFee,
        uint256 _fastTransferId
    ) internal virtual returns (bytes memory) {
        _fastRecieveFrom(msg.sender, _amount);
        return abi.encode(_fastFee, _fastTransferId);
    }

    /**
     * @dev returns an address that indicates who should recieve the bridged tokens.
     * @dev if _fastFees was inlcuded and someone filled the order before the mailbox made the contract call, the filler gets the funds.
     */
    function _getTokenRecipient(
        address _recipient,
        uint256 _amount,
        uint32 _origin,
        bytes calldata _metadata
    ) internal view returns (address) {
        if (_metadata.length == 0) {
            return _recipient;
        }

        // decode metadata to extract `_fastFee` and `_fastTransferId`.
        (uint256 _fastFee, uint256 _fastTransferId) = abi.decode(
            _metadata,
            (uint256, uint256)
        );

        address _fillerAddress = filledFastTransfers[
            _getFastTransfersKey(
                _origin,
                _fastTransferId,
                _amount,
                _fastFee,
                _recipient
            )
        ];
        if (_fillerAddress != address(0)) {
            return _fillerAddress;
        }

        return _recipient;
    }

    /**
     * @dev generates the key for storing the filler address of fast transfers.
     */
    function _getFastTransfersKey(
        uint32 _origin,
        uint256 _fastTransferId,
        uint256 _amount,
        uint256 _fastFee,
        address _recipient
    ) internal pure returns (bytes32) {
        return
            keccak256(
                abi.encodePacked(
                    _origin,
                    _fastTransferId,
                    _amount,
                    _fastFee,
                    _recipient
                )
            );
    }

    /**
     * @dev Should transfer `_amount` of tokens to `_recipient`.
     * @dev The implementation is delegated.
     */
    function _fastTransferTo(
        address _recipient,
        uint256 _amount
    ) internal virtual;

    /**
     * @dev Should collect `amount` of tokens from `_sender`.
     * @dev The implementation is delegated.
     */
    function _fastRecieveFrom(
        address _sender,
        uint256 _amount
    ) internal virtual;
}


// File contracts/token/extensions/FastHypERC20.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity >=0.8.0;



/**
 * @title Hyperlane ERC20 Token Router that extends ERC20 with remote transfer functionality.
 * @author Abacus Works
 * @dev Supply on each chain is not constant but the aggregate supply across all chains is.
 */
contract FastHypERC20 is FastTokenRouter, HypERC20 {
    constructor(
        uint8 __decimals,
        address _mailbox
    ) HypERC20(__decimals, _mailbox) {}

    /**
     * @dev delegates transfer logic to `_transferTo`.
     * @inheritdoc TokenRouter
     */
    function _handle(
        uint32 _origin,
        bytes32 _sender,
        bytes calldata _message
    ) internal virtual override(FastTokenRouter, TokenRouter) {
        FastTokenRouter._handle(_origin, _sender, _message);
    }

    /**
     * @dev Mints `_amount` of tokens to `_recipient`.
     * @inheritdoc FastTokenRouter
     */
    function _fastTransferTo(
        address _recipient,
        uint256 _amount
    ) internal override {
        _mint(_recipient, _amount);
    }

    /**
     * @dev Burns `_amount` of tokens from `_recipient`.
     * @inheritdoc FastTokenRouter
     */
    function _fastRecieveFrom(
        address _sender,
        uint256 _amount
    ) internal override {
        _burn(_sender, _amount);
    }

    function balanceOf(
        address _account
    ) public view virtual override(HypERC20, TokenRouter) returns (uint256) {
        return ERC20Upgradeable.balanceOf(_account);
    }
}


// File contracts/token/HypERC20Collateral.sol

// Original license: SPDX_License_Identifier: Apache-2.0
pragma solidity >=0.8.0;




/**
 * @title Hyperlane ERC20 Token Collateral that wraps an existing ERC20 with remote transfer functionality.
 * @author Abacus Works
 */
contract HypERC20Collateral is TokenRouter {
    using SafeERC20 for IERC20;

    IERC20 public immutable wrappedToken;

    /**
     * @notice Constructor
     * @param erc20 Address of the token to keep as collateral
     */

exec
/bin/bash -lc "rg -n 'initializer|reinitializer|_disableInitializers|delegatecall|call\\{|staticcall\\(|functionCallWithValue|functionCall\\(|sendValue\\(|approve\\(|safeTransferFrom\\(|transferFrom\\(|recover\\(|ECDSA\\.recover|onlyOwner|onlyMailbox|onlyLiquidityLayerRouter' AUDIT_BUNDLE.txt | sed -n '1,260p'" in /tmp/codex-3gxliacl
 succeeded in 0ms:
78:    function sendValue(address payable recipient, uint256 amount) internal {
81:        (bool success, ) = recipient.call{value: amount}("");
103:    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
104:        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
113:    function functionCall(
118:        return functionCallWithValue(target, data, 0, errorMessage);
132:    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
133:        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
137:     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
142:    function functionCallWithValue(
149:        (bool success, bytes memory returndata) = target.call{value: value}(data);
174:        (bool success, bytes memory returndata) = target.staticcall(data);
199:        (bool success, bytes memory returndata) = target.delegatecall(data);
271: * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
272: * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
283: *     function initialize() initializer public {
289: *     function initializeV2() reinitializer(2) public {
295: * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
298: * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
299: * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
307: * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
313: *     _disableInitializers();
336:     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
339:     * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
344:    modifier initializer() {
362:     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
366:     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
369:     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
372:     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
379:    modifier reinitializer(uint8 version) {
390:     * {initializer} and {reinitializer} modifiers, directly or indirectly.
398:     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
405:    function _disableInitializers() internal virtual {
414:     * @dev Returns the highest version that has been initialized. See {reinitializer}.
486: * `onlyOwner`, which can be applied to your functions to restrict their use to
508:    modifier onlyOwner() {
529:     * `onlyOwner` functions. Can only be called by the current owner.
534:    function renounceOwnership() public virtual onlyOwner {
542:    function transferOwnership(address newOwner) public virtual onlyOwner {
656:    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
672:    function safeTransferFrom(address from, address to, uint256 tokenId) external;
690:    function transferFrom(address from, address to, uint256 tokenId) external;
705:    function approve(address to, uint256 tokenId) external;
834:    function approve(address spender, uint256 amount) external returns (bool);
845:    function transferFrom(address from, address to, uint256 amount) external returns (bool);
1019:    function approve(address spender, uint256 amount) public virtual override returns (bool) {
1021:        _approve(owner, spender, amount);
1041:    function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
1062:        _approve(owner, spender, allowance(owner, spender) + addedValue);
1085:            _approve(owner, spender, currentAllowance - subtractedValue);
1191:    function _approve(address owner, address spender, uint256 amount) internal virtual {
1212:                _approve(owner, spender, currentAllowance - amount);
1955:    function approve(address to, uint256 tokenId) public virtual override {
1964:        _approve(to, tokenId);
1993:    function transferFrom(address from, address to, uint256 tokenId) public virtual override {
2003:    function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override {
2004:        safeTransferFrom(from, to, tokenId, "");
2010:    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual override {
2209:    function _approve(address to, uint256 tokenId) internal virtual {
3536: * `onlyOwner`, which can be applied to your functions to restrict their use to
3554:    modifier onlyOwner() {
3575:     * `onlyOwner` functions. Can only be called by the current owner.
3580:    function renounceOwnership() public virtual onlyOwner {
3588:    function transferOwnership(address newOwner) public virtual onlyOwner {
3859: * `onlyOwner` maintenance operations. This gives time for users of the
4200:        (bool success, ) = target.call{value: value}(data);
4410:    function sendValue(address payable recipient, uint256 amount) internal {
4413:        (bool success, ) = recipient.call{value: amount}("");
4435:    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
4436:        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
4445:    function functionCall(
4450:        return functionCallWithValue(target, data, 0, errorMessage);
4464:    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
4465:        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
4469:     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
4474:    function functionCallWithValue(
4481:        (bool success, bytes memory returndata) = target.call{value: value}(data);
4506:        (bool success, bytes memory returndata) = target.staticcall(data);
4531:        (bool success, bytes memory returndata) = target.delegatecall(data);
4903: * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
4926:            let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
4932:            // delegatecall returns 0 on error.
5234:        (bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b");
5249:        (bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440");
5261:    function changeProxyAdmin(ITransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner {
5272:    function upgrade(ITransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner {
5288:    ) public payable virtual onlyOwner {
5468:    function approve(address spender, uint256 amount) external returns (bool);
5479:    function transferFrom(address from, address to, uint256 amount) external returns (bool);
5648:    function approve(address spender, uint256 amount) public virtual override returns (bool) {
5650:        _approve(owner, spender, amount);
5670:    function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
5691:        _approve(owner, spender, allowance(owner, spender) + addedValue);
5714:            _approve(owner, spender, currentAllowance - subtractedValue);
5820:    function _approve(address owner, address spender, uint256 amount) internal virtual {
5841:                _approve(owner, spender, currentAllowance - amount);
5977:    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
6065:        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
6142:    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
6158:    function safeTransferFrom(address from, address to, uint256 tokenId) external;
6176:    function transferFrom(address from, address to, uint256 tokenId) external;
6191:    function approve(address to, uint256 tokenId) external;
6363:    function approve(address to, uint256 tokenId) public virtual override {
6372:        _approve(to, tokenId);
6401:    function transferFrom(address from, address to, uint256 tokenId) public virtual override {
6411:    function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override {
6412:        safeTransferFrom(from, to, tokenId, "");
6418:    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual override {
6617:    function _approve(address to, uint256 tokenId) internal virtual {
6999:    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
7023:    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
7036:        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
7050:        address signer = ecrecover(hash, v, r, s);
7062:    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
8556:    modifier onlyMailbox() {
8574:    function setHook(address _hook) public onlyContractOrNull(_hook) onlyOwner {
8584:    ) public onlyContractOrNull(_module) onlyOwner {
8801:    function unenrollRemoteRouter(uint32 _domain) external virtual onlyOwner {
8813:    ) external virtual onlyOwner {
8825:    ) external virtual onlyOwner {
8839:    ) external virtual onlyOwner {
8856:    ) external payable virtual override onlyMailbox {
9148:    ) external onlyOwner {
9159:    function setDestinationGas(uint32 domain, uint256 gas) external onlyOwner {
9360:    function setAuthorizedHook(bytes32 _hook) external initializer {
9392:                payable(message.recipientAddress()).sendValue(_msgValue);
10153:    ) public initializer {
10165:        (bool success, ) = beneficiary.call{value: address(this).balance}("");
10175:    ) external onlyOwner {
10190:    function setBeneficiary(address _beneficiary) external onlyOwner {
10223:            payable(_refundAddress).sendValue(_overpayment);
10441:    ) external onlyOwner {
10454:    ) external onlyOwner {
10931:    function pause() external onlyOwner {
10935:    function unpause() external onlyOwner {
11035:    function setProtocolFee(uint256 _protocolFee) external onlyOwner {
11043:    function setBeneficiary(address _beneficiary) external onlyOwner {
11051:        payable(beneficiary).sendValue(address(this).balance);
11068:            payable(metadata.refundAddress(message.senderAddress())).sendValue(
11155:    function setHook(uint32 _destination, address _hook) public onlyOwner {
11159:    function setHooks(HookConfig[] calldata configs) external onlyOwner {
11259:    ) external onlyOwner {
11690:            address _signer = ECDSA.recover(_digest, signatureAt(_metadata, i));
12414:        address _signer = ECDSA.recover(_announcementDigest, _signature);
12521:    function pause() external onlyOwner {
12525:    function unpause() external onlyOwner {
12612:    function initialize(address _owner) public initializer {
12627:    ) public initializer {
12645:    ) external onlyOwner {
12653:    function remove(uint32 _domain) external onlyOwner {
12855:            Address.functionCallWithValue(
12862:    function staticcall(
12872:    function staticcall(
12875:        return bytes.concat(_call.callback, staticcall(_call._call));
12889:    function multistaticcall(
12896:            callbacks[i] = staticcall(_calls[i]);
12908:            Address.functionCall(to, calls[i]);
13193:    ) external initializer {
13460:    function setDefaultIsm(address _module) public onlyOwner {
13473:    function setDefaultHook(address _hook) public onlyOwner {
13486:    function setRequiredHook(address _hook) public onlyOwner {
13505:        (bool success, bytes memory returnData) = _recipient.staticcall(
13562:    modifier onlyOwner() {
13567:    function multicall(CallLib.Call[] calldata calls) external onlyOwner {
13668:    ) external initializer {
13692:    ) external onlyOwner {
13707:    ) external onlyOwner {
13780:    ) external payable override onlyMailbox {
14259:    ) external initializer {
14329:            bytes[] memory callbacks = CallLib.multistaticcall(
14406:     * - transferFrom() reverts. For example, if sender's burnToken balance or approved allowance
14434:     * - transferFrom() reverts. For example, if sender's burnToken balance or approved allowance
14532:    modifier onlyLiquidityLayerRouter() {
14550:    ) external initializer {
14566:    ) external onlyLiquidityLayerRouter returns (bytes memory) {
14581:            IERC20(_token).approve(address(tokenMessenger), _amount),
14602:    ) external onlyLiquidityLayerRouter returns (address, uint256) {
14648:    ) external onlyOwner {
14657:    ) external onlyOwner {
14682:    ) external onlyOwner {
14852:    modifier onlyLiquidityLayerRouter() {
14866:    ) public initializer {
14885:    ) external onlyLiquidityLayerRouter returns (bytes memory) {
14896:            IERC20(_token).approve(address(portalTokenBridge), _amount),
14928:    ) external onlyLiquidityLayerRouter returns (address, uint256) {
14996:    ) external onlyOwner {
15078:    ) external initializer {
15097:        IERC20(_token).safeTransferFrom(msg.sender, address(_adapter), _amount);
15169:    ) external onlyOwner {
15266:        token.transferFrom(msg.sender, address(this), _amount);
15409:        _disableInitializers();
15557:        token.transferFrom(msg.sender, address(this), amount);
15710:    function setInterchainSecurityModule(address _ism) external onlyOwner {
16121:    ) public initializer {
16445:    ) external initializer {
16798:        wrappedToken.safeTransferFrom(msg.sender, address(this), _amount);
16871:        wrappedToken.safeTransferFrom(_sender, address(this), _amount);
16919:        wrappedToken.transferFrom(msg.sender, address(this), _tokenId);
16932:        wrappedToken.safeTransferFrom(address(this), _recipient, _tokenId);
16996:    ) external initializer {
17200:        Address.sendValue(payable(_recipient), _amount);

exec
/bin/bash -lc "rg -n 'function initialize\\(|function setAuthorizedHook\\(' AUDIT_BUNDLE.txt | sed -n '1,120p'" in /tmp/codex-3gxliacl
 succeeded in 0ms:
283: *     function initialize() initializer public {
9360:    function setAuthorizedHook(bytes32 _hook) external initializer {
10150:    function initialize(
12612:    function initialize(address _owner) public initializer {
12623:    function initialize(
13188:    function initialize(
13664:    function initialize(
14255:    function initialize(
14545:    function initialize(
14862:    function initialize(
15074:    function initialize(
16027:    function initialize(address _queryRouterAddress) external {
16118:    function initialize(
16441:    function initialize(
16992:    function initialize(

exec
/bin/bash -lc "sed -n '16090,16140p' AUDIT_BUNDLE.txt && sed -n '16436,16458p' AUDIT_BUNDLE.txt && sed -n '16988,17015p' AUDIT_BUNDLE.txt" in /tmp/codex-3gxliacl
 succeeded in 0ms:

    function queryAndPayFor(
        uint32 _destinationDomain,
        address _target,
        bytes calldata _targetData,
        bytes4 _callbackSelector,
        uint256 /*_gasAmount*/
    ) internal {
        queryRouter.query(
            _destinationDomain,
            _target,
            _targetData,
            abi.encodePacked(_callbackSelector)
        );
    }
}


// File contracts/test/TestRouter.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity >=0.6.11;

contract TestRouter is Router {
    event InitializeOverload();

    constructor(address _mailbox) Router(_mailbox) {}

    function initialize(
        address _hook,
        address _interchainSecurityModule
    ) public initializer {
        _MailboxClient_initialize(_hook, _interchainSecurityModule, msg.sender);
    }

    function _handle(uint32, bytes32, bytes calldata) internal pure override {}

    function isRemoteRouter(
        uint32 _domain,
        bytes32 _potentialRemoteRouter
    ) external view returns (bool) {
        return _isRemoteRouter(_domain, _potentialRemoteRouter);
    }

    function mustHaveRemoteRouter(
        uint32 _domain
    ) external view returns (bytes32) {
        return _mustHaveRemoteRouter(_domain);
    }

    function dispatch(uint32 _destination, bytes memory _msg) external payable {
     * @notice Initializes the Hyperlane router, ERC20 metadata, and mints initial supply to deployer.
     * @param _totalSupply The initial supply of the token.
     * @param _name The name of the token.
     * @param _symbol The symbol of the token.
     */
    function initialize(
        uint256 _totalSupply,
        string memory _name,
        string memory _symbol
    ) external initializer {
        // Initialize ERC20 metadata
        __ERC20_init(_name, _symbol);
        _mint(msg.sender, _totalSupply);
    }

    function decimals() public view override returns (uint8) {
        return _decimals;
    }

    function balanceOf(
        address _account
    )
        public
     * @param _mintAmount The amount of NFTs to mint to `msg.sender`.
     * @param _name The name of the token.
     * @param _symbol The symbol of the token.
     */
    function initialize(
        uint256 _mintAmount,
        string memory _name,
        string memory _symbol
    ) external initializer {
        address owner = msg.sender;
        _transferOwnership(owner);

        __ERC721_init(_name, _symbol);
        for (uint256 i = 0; i < _mintAmount; i++) {
            _safeMint(owner, i);
        }
    }

    function balanceOf(
        address _account
    )
        public
        view
        virtual
        override(TokenRouter, ERC721Upgradeable, IERC721Upgradeable)
        returns (uint256)
    {
        return ERC721Upgradeable.balanceOf(_account);

exec
/bin/bash -lc "sed -n '11220,11270p' AUDIT_BUNDLE.txt && sed -n '11182,11210p' AUDIT_BUNDLE.txt" in /tmp/codex-3gxliacl
 succeeded in 0ms:
   @@@@@@@@@       @@@@@@@@@
  @@@@@@@@@       @@@@@@@@@
 @@@@@@@@@       @@@@@@@@@
@@@@@@@@@       @@@@@@@@*/



contract DestinationRecipientRoutingHook is DomainRoutingHook {
    using Message for bytes;

    /// @notice destination => recipient =>custom hook
    mapping(uint32 => mapping(bytes32 => address)) public customHooks;

    constructor(
        address mailbox,
        address owner
    ) DomainRoutingHook(mailbox, owner) {}

    function _postDispatch(
        bytes calldata metadata,
        bytes calldata message
    ) internal override {
        address customHookPreset = customHooks[message.destination()][
            message.recipient()
        ];
        if (customHookPreset != address(0)) {
            IPostDispatchHook(customHookPreset).postDispatch{value: msg.value}(
                metadata,
                message
            );
        } else {
            super._postDispatch(metadata, message);
        }
    }

    function configCustomHook(
        uint32 destinationDomain,
        bytes32 recipient,
        address hook
    ) external onlyOwner {
        customHooks[destinationDomain][recipient] = hook;
    }
}


// File contracts/hooks/routing/FallbackDomainRoutingHook.sol

// Original license: SPDX_License_Identifier: MIT
pragma solidity >=0.8.0;

/*@@@@@@@       @@@@@@@@@
        );
    }

    /// @inheritdoc AbstractPostDispatchHook
    function _quoteDispatch(
        bytes calldata metadata,
        bytes calldata message
    ) internal view virtual override returns (uint256) {
        return _getConfiguredHook(message).quoteDispatch(metadata, message);
    }

    function _getConfiguredHook(
        bytes calldata message
    ) internal view virtual returns (IPostDispatchHook hook) {
        hook = hooks[message.destination()];
        require(
            address(hook) != address(0),
            string.concat(
                "No hook configured for destination: ",
                message.destination().toString()
            )
        );
    }
}


// File contracts/hooks/routing/DestinationRecipientRoutingHook.sol

// Original license: SPDX_License_Identifier: MIT

exec
/bin/bash -lc "nl -ba AUDIT_BUNDLE.txt | sed -n '9190,9245p'" in /tmp/codex-3gxliacl
 succeeded in 0ms:
  9190	pragma solidity >=0.8.0;
  9191	
  9192	/*@@@@@@@       @@@@@@@@@
  9193	 @@@@@@@@@       @@@@@@@@@
  9194	  @@@@@@@@@       @@@@@@@@@
  9195	   @@@@@@@@@       @@@@@@@@@
  9196	    @@@@@@@@@@@@@@@@@@@@@@@@@
  9197	     @@@@@  HYPERLANE  @@@@@@@
  9198	    @@@@@@@@@@@@@@@@@@@@@@@@@
  9199	   @@@@@@@@@       @@@@@@@@@
  9200	  @@@@@@@@@       @@@@@@@@@
  9201	 @@@@@@@@@       @@@@@@@@@
  9202	@@@@@@@@@       @@@@@@@@*/
  9203	
  9204	// ============ Internal Imports ============
  9205	
  9206	
  9207	/**
  9208	 * @title AbstractPostDispatch
  9209	 * @notice Abstract post dispatch hook supporting the current global hook metadata variant.
  9210	 */
  9211	abstract contract AbstractPostDispatchHook is IPostDispatchHook {
  9212	    using StandardHookMetadata for bytes;
  9213	
  9214	    // ============ External functions ============
  9215	
  9216	    /// @inheritdoc IPostDispatchHook
  9217	    function supportsMetadata(
  9218	        bytes calldata metadata
  9219	    ) public pure virtual override returns (bool) {
  9220	        return
  9221	            metadata.length == 0 ||
  9222	            metadata.variant() == StandardHookMetadata.VARIANT;
  9223	    }
  9224	
  9225	    /// @inheritdoc IPostDispatchHook
  9226	    function postDispatch(
  9227	        bytes calldata metadata,
  9228	        bytes calldata message
  9229	    ) external payable override {
  9230	        require(
  9231	            supportsMetadata(metadata),
  9232	            "AbstractPostDispatchHook: invalid metadata variant"
  9233	        );
  9234	        _postDispatch(metadata, message);
  9235	    }
  9236	
  9237	    /// @inheritdoc IPostDispatchHook
  9238	    function quoteDispatch(
  9239	        bytes calldata metadata,
  9240	        bytes calldata message
  9241	    ) public view override returns (uint256) {
  9242	        require(
  9243	            supportsMetadata(metadata),
  9244	            "AbstractPostDispatchHook: invalid metadata variant"
  9245	        );

exec
/bin/bash -lc "nl -ba AUDIT_BUNDLE.txt | sed -n '9460,9518p'" in /tmp/codex-3gxliacl
 succeeded in 0ms:
  9460	    // left-padded address for ISM to verify messages
  9461	    bytes32 public immutable ism;
  9462	    // Domain of chain on which the ISM is deployed
  9463	    uint32 public immutable destinationDomain;
  9464	
  9465	    // ============ Constructor ============
  9466	
  9467	    constructor(
  9468	        address _mailbox,
  9469	        uint32 _destinationDomain,
  9470	        bytes32 _ism
  9471	    ) MailboxClient(_mailbox) {
  9472	        require(_ism != bytes32(0), "AbstractMessageIdAuthHook: invalid ISM");
  9473	        require(
  9474	            _destinationDomain != 0,
  9475	            "AbstractMessageIdAuthHook: invalid destination domain"
  9476	        );
  9477	        ism = _ism;
  9478	        destinationDomain = _destinationDomain;
  9479	    }
  9480	
  9481	    /// @inheritdoc IPostDispatchHook
  9482	    function hookType() external pure returns (uint8) {
  9483	        return uint8(IPostDispatchHook.Types.ID_AUTH_ISM);
  9484	    }
  9485	
  9486	    // ============ Internal functions ============
  9487	
  9488	    /// @inheritdoc AbstractPostDispatchHook
  9489	    function _postDispatch(
  9490	        bytes calldata metadata,
  9491	        bytes calldata message
  9492	    ) internal override {
  9493	        bytes32 id = message.id();
  9494	        require(
  9495	            _isLatestDispatched(id),
  9496	            "AbstractMessageIdAuthHook: message not latest dispatched"
  9497	        );
  9498	        require(
  9499	            message.destination() == destinationDomain,
  9500	            "AbstractMessageIdAuthHook: invalid destination domain"
  9501	        );
  9502	        bytes memory payload = abi.encodeCall(
  9503	            AbstractMessageIdAuthorizedIsm.verifyMessageId,
  9504	            id
  9505	        );
  9506	        _sendMessageId(metadata, payload);
  9507	    }
  9508	
  9509	    /**
  9510	     * @notice Send a message to the ISM.
  9511	     * @param metadata The metadata for the hook caller
  9512	     * @param payload The payload for call to the ISM
  9513	     */
  9514	    function _sendMessageId(
  9515	        bytes calldata metadata,
  9516	        bytes memory payload
  9517	    ) internal virtual;
  9518	}

exec
/bin/bash -lc "nl -ba AUDIT_BUNDLE.txt | sed -n '10700,10770p'" in /tmp/codex-3gxliacl
 succeeded in 0ms:
 10700	    @@@@@@@@@@@@@@@@@@@@@@@@@
 10701	     @@@@@  HYPERLANE  @@@@@@@
 10702	    @@@@@@@@@@@@@@@@@@@@@@@@@
 10703	   @@@@@@@@@       @@@@@@@@@
 10704	  @@@@@@@@@       @@@@@@@@@
 10705	 @@@@@@@@@       @@@@@@@@@
 10706	@@@@@@@@@       @@@@@@@@*/
 10707	
 10708	
 10709	
 10710	
 10711	
 10712	
 10713	
 10714	contract MerkleTreeHook is AbstractPostDispatchHook, MailboxClient, Indexed {
 10715	    using Message for bytes;
 10716	    using MerkleLib for MerkleLib.Tree;
 10717	    using StandardHookMetadata for bytes;
 10718	
 10719	    // An incremental merkle tree used to store outbound message IDs.
 10720	    MerkleLib.Tree internal _tree;
 10721	
 10722	    event InsertedIntoTree(bytes32 messageId, uint32 index);
 10723	
 10724	    constructor(address _mailbox) MailboxClient(_mailbox) {}
 10725	
 10726	    // count cannot exceed 2**TREE_DEPTH, see MerkleLib.sol
 10727	    function count() public view returns (uint32) {
 10728	        return uint32(_tree.count);
 10729	    }
 10730	
 10731	    function root() public view returns (bytes32) {
 10732	        return _tree.root();
 10733	    }
 10734	
 10735	    function tree() public view returns (MerkleLib.Tree memory) {
 10736	        return _tree;
 10737	    }
 10738	
 10739	    function latestCheckpoint() external view returns (bytes32, uint32) {
 10740	        return (root(), count() - 1);
 10741	    }
 10742	
 10743	    // ============ External Functions ============
 10744	
 10745	    /// @inheritdoc IPostDispatchHook
 10746	    function hookType() external pure override returns (uint8) {
 10747	        return uint8(IPostDispatchHook.Types.MERKLE_TREE);
 10748	    }
 10749	
 10750	    // ============ Internal Functions ============
 10751	
 10752	    /// @inheritdoc AbstractPostDispatchHook
 10753	    function _postDispatch(
 10754	        bytes calldata,
 10755	        /*metadata*/
 10756	        bytes calldata message
 10757	    ) internal override {
 10758	        require(msg.value == 0, "MerkleTreeHook: no value expected");
 10759	
 10760	        // ensure messages which were not dispatched are not inserted into the tree
 10761	        bytes32 id = message.id();
 10762	        require(_isLatestDispatched(id), "message not dispatching");
 10763	
 10764	        uint32 index = count();
 10765	        _tree.insert(id);
 10766	        emit InsertedIntoTree(id, index);
 10767	    }
 10768	
 10769	    /// @inheritdoc AbstractPostDispatchHook
 10770	    function _quoteDispatch(

exec
/bin/bash -lc "nl -ba AUDIT_BUNDLE.txt | sed -n '13180,13215p'" in /tmp/codex-3gxliacl
 succeeded in 0ms:
 13180	    event RequiredHookSet(address indexed hook);
 13181	
 13182	    // ============ Constructor ============
 13183	    constructor(uint32 _localDomain) {
 13184	        localDomain = _localDomain;
 13185	    }
 13186	
 13187	    // ============ Initializers ============
 13188	    function initialize(
 13189	        address _owner,
 13190	        address _defaultIsm,
 13191	        address _defaultHook,
 13192	        address _requiredHook
 13193	    ) external initializer {
 13194	        __Ownable_init();
 13195	        setDefaultIsm(_defaultIsm);
 13196	        setDefaultHook(_defaultHook);
 13197	        setRequiredHook(_requiredHook);
 13198	        transferOwnership(_owner);
 13199	    }
 13200	
 13201	    // ============ External Functions ============
 13202	    /**
 13203	     * @notice Dispatches a message to the destination domain & recipient
 13204	     * using the default hook and empty metadata.
 13205	     * @param _destinationDomain Domain of destination chain
 13206	     * @param _recipientAddress Address of recipient on destination chain as bytes32
 13207	     * @param _messageBody Raw bytes content of message body
 13208	     * @return The message ID inserted into the Mailbox's merkle tree
 13209	     */
 13210	    function dispatch(
 13211	        uint32 _destinationDomain,
 13212	        bytes32 _recipientAddress,
 13213	        bytes calldata _messageBody
 13214	    ) external payable override returns (bytes32) {
 13215	        return

exec
/bin/bash -lc "nl -ba AUDIT_BUNDLE.txt | sed -n '9352,9372p'" in /tmp/codex-3gxliacl
 succeeded in 0ms:
  9352	
  9353	    // ============ Events ============
  9354	
  9355	    /// @notice Emitted when a message is received from the external bridge
  9356	    event ReceivedMessage(bytes32 indexed messageId);
  9357	
  9358	    // ============ Initializer ============
  9359	
  9360	    function setAuthorizedHook(bytes32 _hook) external initializer {
  9361	        require(
  9362	            _hook != bytes32(0),
  9363	            "AbstractMessageIdAuthorizedIsm: invalid authorized hook"
  9364	        );
  9365	        authorizedHook = _hook;
  9366	    }
  9367	
  9368	    // ============ External Functions ============
  9369	
  9370	    /**
  9371	     * @notice Verify a message was received by ISM.
  9372	     * @param message Message to verify.

exec
/bin/bash -lc "nl -ba AUDIT_BUNDLE.txt | sed -n '10146,10162p'" in /tmp/codex-3gxliacl
 succeeded in 0ms:
 10146	    /**
 10147	     * @param _owner The owner of the contract.
 10148	     * @param _beneficiary The beneficiary.
 10149	     */
 10150	    function initialize(
 10151	        address _owner,
 10152	        address _beneficiary
 10153	    ) public initializer {
 10154	        __Ownable_init();
 10155	        _transferOwnership(_owner);
 10156	        _setBeneficiary(_beneficiary);
 10157	    }
 10158	
 10159	    /**
 10160	     * @notice Transfers the entire native token balance to the beneficiary.
 10161	     * @dev The beneficiary must be able to receive native tokens.
 10162	     */

exec
/bin/bash -lc "nl -ba AUDIT_BUNDLE.txt | sed -n '13660,13684p'" in /tmp/codex-3gxliacl
 succeeded in 0ms:
 13660	     * @param _interchainGasPaymaster Unused but required by HyperlaneConnectionClient
 13661	     * @param _interchainSecurityModule The address of the local ISM contract
 13662	     * @param _owner The address with owner privileges
 13663	     */
 13664	    function initialize(
 13665	        address _interchainGasPaymaster,
 13666	        address _interchainSecurityModule,
 13667	        address _owner
 13668	    ) external initializer {
 13669	        _MailboxClient_initialize(
 13670	            _interchainGasPaymaster,
 13671	            _interchainSecurityModule,
 13672	            _owner
 13673	        );
 13674	
 13675	        implementation = address(new OwnableMulticall(address(this)));
 13676	        // cannot be stored immutably because it is dynamically sized
 13677	        bytes memory _bytecode = MinimalProxy.bytecode(implementation);
 13678	        bytecodeHash = keccak256(_bytecode);
 13679	    }
 13680	
 13681	    /**
 13682	     * @notice Registers the address of remote InterchainAccountRouter
 13683	     * and ISM contracts to use as a default when making interchain calls
 13684	     * @param _destination The remote domain

exec
/bin/bash -lc "nl -ba AUDIT_BUNDLE.txt | sed -n '14250,14272p'" in /tmp/codex-3gxliacl
 succeeded in 0ms:
 14250	     * @notice Initializes the Router contract with Hyperlane core contracts and the address of the interchain security module.
 14251	     * @param _interchainGasPaymaster The address of the interchain gas paymaster contract.
 14252	     * @param _interchainSecurityModule The address of the interchain security module contract.
 14253	     * @param _owner The address with owner privileges.
 14254	     */
 14255	    function initialize(
 14256	        address _interchainGasPaymaster,
 14257	        address _interchainSecurityModule,
 14258	        address _owner
 14259	    ) external initializer {
 14260	        _MailboxClient_initialize(
 14261	            _interchainGasPaymaster,
 14262	            _interchainSecurityModule,
 14263	            _owner
 14264	        );
 14265	    }
 14266	
 14267	    /**
 14268	     * @notice Dispatches a sequence of static calls (query) to the destination domain and set of callbacks to resolve the results on the dispatcher.
 14269	     * @param _destination The domain of the chain to query.
 14270	     * @param _to The address of the contract to query
 14271	     * @param _data The calldata encoding the query
 14272	     * @param _callback The calldata of the callback that will be made on the sender.

exec
/bin/bash -lc "nl -ba AUDIT_BUNDLE.txt | sed -n '14542,14560p'" in /tmp/codex-3gxliacl
 succeeded in 0ms:
 14542	     * @param _circleMessageTransmitter The Circle MessageTransmitter contract.
 14543	     * @param _liquidityLayerRouter The LiquidityLayerRouter contract.
 14544	     */
 14545	    function initialize(
 14546	        address _owner,
 14547	        address _tokenMessenger,
 14548	        address _circleMessageTransmitter,
 14549	        address _liquidityLayerRouter
 14550	    ) external initializer {
 14551	        __Ownable_init();
 14552	        _transferOwnership(_owner);
 14553	
 14554	        tokenMessenger = ITokenMessenger(_tokenMessenger);
 14555	        circleMessageTransmitter = ICircleMessageTransmitter(
 14556	            _circleMessageTransmitter
 14557	        );
 14558	        liquidityLayerRouter = _liquidityLayerRouter;
 14559	    }
 14560	

exec
/bin/bash -lc "nl -ba AUDIT_BUNDLE.txt | sed -n '14860,14878p'" in /tmp/codex-3gxliacl
 succeeded in 0ms:
 14860	     * @param _liquidityLayerRouter The LiquidityLayerRouter contract.
 14861	     */
 14862	    function initialize(
 14863	        address _owner,
 14864	        address _portalTokenBridge,
 14865	        address _liquidityLayerRouter
 14866	    ) public initializer {
 14867	        // Transfer ownership of the contract to deployer
 14868	        _transferOwnership(_owner);
 14869	
 14870	        portalTokenBridge = IPortalTokenBridge(_portalTokenBridge);
 14871	        liquidityLayerRouter = _liquidityLayerRouter;
 14872	    }
 14873	
 14874	    /**
 14875	     * Sends tokens as requested by the router
 14876	     * @param _destinationDomain The hyperlane domain of the destination
 14877	     * @param _token The token address
 14878	     * @param _amount The amount of tokens to send

exec
/bin/bash -lc "nl -ba AUDIT_BUNDLE.txt | sed -n '15072,15090p'" in /tmp/codex-3gxliacl
 succeeded in 0ms:
 15072	     * @param _owner The address with owner privileges.
 15073	     */
 15074	    function initialize(
 15075	        address _interchainGasPaymaster,
 15076	        address _interchainSecurityModule,
 15077	        address _owner
 15078	    ) external initializer {
 15079	        _MailboxClient_initialize(
 15080	            _interchainGasPaymaster,
 15081	            _interchainSecurityModule,
 15082	            _owner
 15083	        );
 15084	    }
 15085	
 15086	    function dispatchWithTokens(
 15087	        uint32 _destinationDomain,
 15088	        bytes32 _recipientAddress,
 15089	        address _token,
 15090	        uint256 _amount,

exec
/bin/bash -lc "nl -ba AUDIT_BUNDLE.txt | sed -n '16438,16454p'" in /tmp/codex-3gxliacl
 succeeded in 0ms:
 16438	     * @param _name The name of the token.
 16439	     * @param _symbol The symbol of the token.
 16440	     */
 16441	    function initialize(
 16442	        uint256 _totalSupply,
 16443	        string memory _name,
 16444	        string memory _symbol
 16445	    ) external initializer {
 16446	        // Initialize ERC20 metadata
 16447	        __ERC20_init(_name, _symbol);
 16448	        _mint(msg.sender, _totalSupply);
 16449	    }
 16450	
 16451	    function decimals() public view override returns (uint8) {
 16452	        return _decimals;
 16453	    }
 16454	

exec
/bin/bash -lc "nl -ba AUDIT_BUNDLE.txt | sed -n '16990,17010p'" in /tmp/codex-3gxliacl
 succeeded in 0ms:
 16990	     * @param _symbol The symbol of the token.
 16991	     */
 16992	    function initialize(
 16993	        uint256 _mintAmount,
 16994	        string memory _name,
 16995	        string memory _symbol
 16996	    ) external initializer {
 16997	        address owner = msg.sender;
 16998	        _transferOwnership(owner);
 16999	
 17000	        __ERC721_init(_name, _symbol);
 17001	        for (uint256 i = 0; i < _mintAmount; i++) {
 17002	            _safeMint(owner, i);
 17003	        }
 17004	    }
 17005	
 17006	    function balanceOf(
 17007	        address _account
 17008	    )
 17009	        public
 17010	        view

exec
/bin/bash -lc "nl -ba AUDIT_BUNDLE.txt | sed -n '12608,12638p'" in /tmp/codex-3gxliacl
 succeeded in 0ms:
 12608	
 12609	    /**
 12610	     * @param _owner The owner of the contract.
 12611	     */
 12612	    function initialize(address _owner) public initializer {
 12613	        __Ownable_init();
 12614	        _transferOwnership(_owner);
 12615	    }
 12616	
 12617	    /**
 12618	     * @notice Sets the ISMs to be used for the specified origin domains
 12619	     * @param _owner The owner of the contract.
 12620	     * @param _domains The origin domains
 12621	     * @param __modules The ISMs to use to verify messages
 12622	     */
 12623	    function initialize(
 12624	        address _owner,
 12625	        uint32[] calldata _domains,
 12626	        IInterchainSecurityModule[] calldata __modules
 12627	    ) public initializer {
 12628	        __Ownable_init();
 12629	        require(_domains.length == __modules.length, "length mismatch");
 12630	        uint256 _length = _domains.length;
 12631	        for (uint256 i = 0; i < _length; ++i) {
 12632	            _set(_domains[i], address(__modules[i]));
 12633	        }
 12634	        _transferOwnership(_owner);
 12635	    }
 12636	
 12637	    /**
 12638	     * @notice Sets the ISM to be used for the specified origin domain

exec
/bin/bash -lc "nl -ba AUDIT_BUNDLE.txt | sed -n '11184,11208p'" in /tmp/codex-3gxliacl
 succeeded in 0ms:
 11184	
 11185	    /// @inheritdoc AbstractPostDispatchHook
 11186	    function _quoteDispatch(
 11187	        bytes calldata metadata,
 11188	        bytes calldata message
 11189	    ) internal view virtual override returns (uint256) {
 11190	        return _getConfiguredHook(message).quoteDispatch(metadata, message);
 11191	    }
 11192	
 11193	    function _getConfiguredHook(
 11194	        bytes calldata message
 11195	    ) internal view virtual returns (IPostDispatchHook hook) {
 11196	        hook = hooks[message.destination()];
 11197	        require(
 11198	            address(hook) != address(0),
 11199	            string.concat(
 11200	                "No hook configured for destination: ",
 11201	                message.destination().toString()
 11202	            )
 11203	        );
 11204	    }
 11205	}
 11206	
 11207	
 11208	// File contracts/hooks/routing/DestinationRecipientRoutingHook.sol

exec
/bin/bash -lc "nl -ba AUDIT_BUNDLE.txt | sed -n '11220,11256p'" in /tmp/codex-3gxliacl
 succeeded in 0ms:
 11220	   @@@@@@@@@       @@@@@@@@@
 11221	  @@@@@@@@@       @@@@@@@@@
 11222	 @@@@@@@@@       @@@@@@@@@
 11223	@@@@@@@@@       @@@@@@@@*/
 11224	
 11225	
 11226	
 11227	contract DestinationRecipientRoutingHook is DomainRoutingHook {
 11228	    using Message for bytes;
 11229	
 11230	    /// @notice destination => recipient =>custom hook
 11231	    mapping(uint32 => mapping(bytes32 => address)) public customHooks;
 11232	
 11233	    constructor(
 11234	        address mailbox,
 11235	        address owner
 11236	    ) DomainRoutingHook(mailbox, owner) {}
 11237	
 11238	    function _postDispatch(
 11239	        bytes calldata metadata,
 11240	        bytes calldata message
 11241	    ) internal override {
 11242	        address customHookPreset = customHooks[message.destination()][
 11243	            message.recipient()
 11244	        ];
 11245	        if (customHookPreset != address(0)) {
 11246	            IPostDispatchHook(customHookPreset).postDispatch{value: msg.value}(
 11247	                metadata,
 11248	                message
 11249	            );
 11250	        } else {
 11251	            super._postDispatch(metadata, message);
 11252	        }
 11253	    }
 11254	
 11255	    function configCustomHook(
 11256	        uint32 destinationDomain,

codex
{"no_findings":false,"summary":"Found 3 issues: multiple constructor-deployed contracts can be hijacked through permissionless initializers, mailbox-authenticated hooks can be triggered directly by anyone for the current latest message, and recipient-specific routing quotes do not match execution.","findings":[{"severity":"high","category":"auth","title":"Permissionless initializers let the first caller seize control and mint supply","exploit_scenario":"Several production contracts are deployed with constructors but defer critical setup to unrestricted `initializer` functions. If deployment and initialization are not atomic, an attacker can front-run the intended initializer call, become owner, install malicious hooks/ISMs/bridge endpoints, or mint the full initial token/NFT supply to themselves. For example, hijacking `Mailbox.initialize` gives the attacker control over `defaultIsm/defaultHook/requiredHook`, while hijacking `HypERC20.initialize` or `HypERC721.initialize` mints the initial supply to the attacker.","recommendation":"Do not expose public initialization for constructor-deployed instances. Move critical setup into the constructor or gate initialization to the constructor-established owner with a separate one-time guard. If these are meant to be proxy implementations, disable initializers on the implementation and initialize atomically via proxy constructor calldata.","evidence":"`initialize`/`setAuthorizedHook` are externally callable with only the OZ `initializer` modifier, which enforces one-time execution but does not authenticate the caller. Some of these initializers also mint to `msg.sender` or rewrite owner/configuration.","locations":["AUDIT_BUNDLE.txt:9360 (contracts/isms/hook/AbstractMessageIdAuthorizedIsm.sol)","AUDIT_BUNDLE.txt:10150 (contracts/hooks/igp/InterchainGasPaymaster.sol)","AUDIT_BUNDLE.txt:12612 (contracts/isms/routing/DomainRoutingIsm.sol)","AUDIT_BUNDLE.txt:12623 (contracts/isms/routing/DomainRoutingIsm.sol)","AUDIT_BUNDLE.txt:13188 (contracts/Mailbox.sol)","AUDIT_BUNDLE.txt:13664 (contracts/middleware/InterchainAccountRouter.sol)","AUDIT_BUNDLE.txt:14255 (contracts/middleware/InterchainQueryRouter.sol)","AUDIT_BUNDLE.txt:14545 (contracts/middleware/liquidity-layer/adapters/CircleBridgeAdapter.sol)","AUDIT_BUNDLE.txt:14862 (contracts/middleware/liquidity-layer/adapters/PortalAdapter.sol)","AUDIT_BUNDLE.txt:15074 (contracts/middleware/liquidity-layer/LiquidityLayerRouter.sol)","AUDIT_BUNDLE.txt:16441 (contracts/token/HypERC20.sol)","AUDIT_BUNDLE.txt:16992 (contracts/token/HypERC721.sol)"]},{"severity":"high","category":"auth","title":"Anyone can call post-dispatch hooks directly for the current latest message","exploit_scenario":"After any legitimate dispatch, the full message bytes are public in the `Dispatch` event and `latestDispatchedId` stays set until the next dispatch. Because `AbstractPostDispatchHook.postDispatch` is permissionless, an attacker can call `MerkleTreeHook.postDispatch` directly and insert the same message ID into the Merkle tree again, corrupting checkpoint state. The same pattern also lets an attacker directly trigger message-id authorization hooks (`ERC5164Hook`/`OPStackHook`) for the current latest message, even if that message did not actually opt into those hooks through mailbox dispatch.","recommendation":"Require `msg.sender == address(mailbox)` for hooks whose security depends on mailbox state, or override `postDispatch` in those hooks to enforce mailbox-only access. Add single-use guards per message ID where duplicate execution would be unsafe.","evidence":"`AbstractPostDispatchHook.postDispatch` has no caller check. `MerkleTreeHook` and `AbstractMessageIdAuthHook` only verify that the supplied message matches `mailbox.latestDispatchedId()`, which any external caller can satisfy by replaying the just-emitted message bytes.","locations":["AUDIT_BUNDLE.txt:9226 (contracts/hooks/libs/AbstractPostDispatchHook.sol)","AUDIT_BUNDLE.txt:9489 (contracts/hooks/libs/AbstractMessageIdAuthHook.sol)","AUDIT_BUNDLE.txt:10753 (contracts/hooks/MerkleTreeHook.sol)"]},{"severity":"low","category":"other","title":"DestinationRecipientRoutingHook quotes the wrong hook for recipient-specific routes","exploit_scenario":"If the owner configures a `customHooks[destination][recipient]`, dispatch execution will route to that custom hook, but fee quoting still uses the destination-level hook from `DomainRoutingHook`. Users relying on `quoteDispatch` can underpay and have dispatches revert, making recipient-specific routes unusable unless callers manually overpay.","recommendation":"Override `_quoteDispatch` in `DestinationRecipientRoutingHook` so it resolves the same hook that `_postDispatch` will actually call, including recipient-specific overrides.","evidence":"`DestinationRecipientRoutingHook._postDispatch` consults `customHooks[destination][recipient]`, but inherited `DomainRoutingHook._quoteDispatch` only calls `_getConfiguredHook(message)`, which is destination-only and never checks the recipient override map.","locations":["AUDIT_BUNDLE.txt:11186 (contracts/hooks/routing/DomainRoutingHook.sol)","AUDIT_BUNDLE.txt:11238 (contracts/hooks/routing/DestinationRecipientRoutingHook.sol)"]}]}
tokens used
145,563
Metadata
{
    "codex": {
        "ran_at": "2026-04-04T03:30:25.678088+00:00",
        "returncode": 0
    },
    "project": {
        "mode": "source",
        "file_count": 1,
        "import_count": 0,
        "first_party_contracts_count": 1
    },
    "summary": "Found 3 issues: multiple constructor-deployed contracts can be hijacked through permissionless initializers, mailbox-authenticated hooks can be triggered directly by anyone for the current latest message, and recipient-specific routing quotes do not match execution.",
    "raw_final": {
        "summary": "Found 3 issues: multiple constructor-deployed contracts can be hijacked through permissionless initializers, mailbox-authenticated hooks can be triggered directly by anyone for the current latest message, and recipient-specific routing quotes do not match execution.",
        "findings": [
            {
                "title": "Permissionless initializers let the first caller seize control and mint supply",
                "category": "auth",
                "evidence": "`initialize`/`setAuthorizedHook` are externally callable with only the OZ `initializer` modifier, which enforces one-time execution but does not authenticate the caller. Some of these initializers also mint to `msg.sender` or rewrite owner/configuration.",
                "severity": "high",
                "locations": [
                    "AUDIT_BUNDLE.txt:9360 (contracts/isms/hook/AbstractMessageIdAuthorizedIsm.sol)",
                    "AUDIT_BUNDLE.txt:10150 (contracts/hooks/igp/InterchainGasPaymaster.sol)",
                    "AUDIT_BUNDLE.txt:12612 (contracts/isms/routing/DomainRoutingIsm.sol)",
                    "AUDIT_BUNDLE.txt:12623 (contracts/isms/routing/DomainRoutingIsm.sol)",
                    "AUDIT_BUNDLE.txt:13188 (contracts/Mailbox.sol)",
                    "AUDIT_BUNDLE.txt:13664 (contracts/middleware/InterchainAccountRouter.sol)",
                    "AUDIT_BUNDLE.txt:14255 (contracts/middleware/InterchainQueryRouter.sol)",
                    "AUDIT_BUNDLE.txt:14545 (contracts/middleware/liquidity-layer/adapters/CircleBridgeAdapter.sol)",
                    "AUDIT_BUNDLE.txt:14862 (contracts/middleware/liquidity-layer/adapters/PortalAdapter.sol)",
                    "AUDIT_BUNDLE.txt:15074 (contracts/middleware/liquidity-layer/LiquidityLayerRouter.sol)",
                    "AUDIT_BUNDLE.txt:16441 (contracts/token/HypERC20.sol)",
                    "AUDIT_BUNDLE.txt:16992 (contracts/token/HypERC721.sol)"
                ],
                "recommendation": "Do not expose public initialization for constructor-deployed instances. Move critical setup into the constructor or gate initialization to the constructor-established owner with a separate one-time guard. If these are meant to be proxy implementations, disable initializers on the implementation and initialize atomically via proxy constructor calldata.",
                "exploit_scenario": "Several production contracts are deployed with constructors but defer critical setup to unrestricted `initializer` functions. If deployment and initialization are not atomic, an attacker can front-run the intended initializer call, become owner, install malicious hooks/ISMs/bridge endpoints, or mint the full initial token/NFT supply to themselves. For example, hijacking `Mailbox.initialize` gives the attacker control over `defaultIsm/defaultHook/requiredHook`, while hijacking `HypERC20.initialize` or `HypERC721.initialize` mints the initial supply to the attacker."
            },
            {
                "title": "Anyone can call post-dispatch hooks directly for the current latest message",
                "category": "auth",
                "evidence": "`AbstractPostDispatchHook.postDispatch` has no caller check. `MerkleTreeHook` and `AbstractMessageIdAuthHook` only verify that the supplied message matches `mailbox.latestDispatchedId()`, which any external caller can satisfy by replaying the just-emitted message bytes.",
                "severity": "high",
                "locations": [
                    "AUDIT_BUNDLE.txt:9226 (contracts/hooks/libs/AbstractPostDispatchHook.sol)",
                    "AUDIT_BUNDLE.txt:9489 (contracts/hooks/libs/AbstractMessageIdAuthHook.sol)",
                    "AUDIT_BUNDLE.txt:10753 (contracts/hooks/MerkleTreeHook.sol)"
                ],
                "recommendation": "Require `msg.sender == address(mailbox)` for hooks whose security depends on mailbox state, or override `postDispatch` in those hooks to enforce mailbox-only access. Add single-use guards per message ID where duplicate execution would be unsafe.",
                "exploit_scenario": "After any legitimate dispatch, the full message bytes are public in the `Dispatch` event and `latestDispatchedId` stays set until the next dispatch. Because `AbstractPostDispatchHook.postDispatch` is permissionless, an attacker can call `MerkleTreeHook.postDispatch` directly and insert the same message ID into the Merkle tree again, corrupting checkpoint state. The same pattern also lets an attacker directly trigger message-id authorization hooks (`ERC5164Hook`/`OPStackHook`) for the current latest message, even if that message did not actually opt into those hooks through mailbox dispatch."
            },
            {
                "title": "DestinationRecipientRoutingHook quotes the wrong hook for recipient-specific routes",
                "category": "other",
                "evidence": "`DestinationRecipientRoutingHook._postDispatch` consults `customHooks[destination][recipient]`, but inherited `DomainRoutingHook._quoteDispatch` only calls `_getConfiguredHook(message)`, which is destination-only and never checks the recipient override map.",
                "severity": "low",
                "locations": [
                    "AUDIT_BUNDLE.txt:11186 (contracts/hooks/routing/DomainRoutingHook.sol)",
                    "AUDIT_BUNDLE.txt:11238 (contracts/hooks/routing/DestinationRecipientRoutingHook.sol)"
                ],
                "recommendation": "Override `_quoteDispatch` in `DestinationRecipientRoutingHook` so it resolves the same hook that `_postDispatch` will actually call, including recipient-specific overrides.",
                "exploit_scenario": "If the owner configures a `customHooks[destination][recipient]`, dispatch execution will route to that custom hook, but fee quoting still uses the destination-level hook from `DomainRoutingHook`. Users relying on `quoteDispatch` can underpay and have dispatches revert, making recipient-specific routes unusable unless callers manually overpay."
            }
        ],
        "no_findings": false
    },
    "no_findings": false,
    "schema_version": 1
}

Opcode Heuristics

tool.cast_disasm
Delegatecall
0
Selfdestruct
0
CREATE2
0
CALL-family (heavy)
3
EXT*/BALANCE
3
Total opcodes
4107
Flags
No heuristic flags raised.
View cast disassembly output
00000000: PUSH1 0x80
00000002: PUSH1 0x40
00000004: MSTORE
00000005: PUSH1 0x04
00000007: CALLDATASIZE
00000008: LT
00000009: PUSH2 0x0179
0000000c: JUMPI
0000000d: PUSH1 0x00
0000000f: CALLDATALOAD
00000010: PUSH1 0xe0
00000012: SHR
00000013: DUP1
00000014: PUSH4 0x81b4e8b4
00000019: GT
0000001a: PUSH2 0x00cb
0000001d: JUMPI
0000001e: DUP1
0000001f: PUSH4 0xd5438eae
00000024: GT
00000025: PUSH2 0x007f
00000028: JUMPI
00000029: DUP1
0000002a: PUSH4 0xefae508a
0000002f: GT
00000030: PUSH2 0x0059
00000033: JUMPI
00000034: DUP1
00000035: PUSH4 0xefae508a
0000003a: EQ
0000003b: PUSH2 0x04b5
0000003e: JUMPI
0000003f: DUP1
00000040: PUSH4 0xf2ed8c53
00000045: EQ
00000046: PUSH2 0x04d5
00000049: JUMPI
0000004a: DUP1
0000004b: PUSH4 0xf2fde38b
00000050: EQ
00000051: PUSH2 0x04f5
00000054: JUMPI
00000055: PUSH1 0x00
00000057: DUP1
00000058: REVERT
00000059: JUMPDEST
0000005a: DUP1
0000005b: PUSH4 0xd5438eae
00000060: EQ
00000061: PUSH2 0x0434
00000064: JUMPI
00000065: DUP1
00000066: PUSH4 0xde523cf3
0000006b: EQ
0000006c: PUSH2 0x0468
0000006f: JUMPI
00000070: DUP1
00000071: PUSH4 0xe9198bf9
00000076: EQ
00000077: PUSH2 0x0495
0000007a: JUMPI
0000007b: PUSH1 0x00
0000007d: DUP1
0000007e: REVERT
0000007f: JUMPDEST
00000080: DUP1
00000081: PUSH4 0x8da5cb5b
00000086: GT
00000087: PUSH2 0x00b0
0000008a: JUMPI
0000008b: DUP1
0000008c: PUSH4 0x8da5cb5b
00000091: EQ
00000092: PUSH2 0x03c9
00000095: JUMPI
00000096: DUP1
00000097: PUSH4 0xb1bd6436
0000009c: EQ
0000009d: PUSH2 0x03f4
000000a0: JUMPI
000000a1: DUP1
000000a2: PUSH4 0xb49c53a7
000000a7: EQ
000000a8: PUSH2 0x0414
000000ab: JUMPI
000000ac: PUSH1 0x00
000000ae: DUP1
000000af: REVERT
000000b0: JUMPDEST
000000b1: DUP1
000000b2: PUSH4 0x81b4e8b4
000000b7: EQ
000000b8: PUSH2 0x036d
000000bb: JUMPI
000000bc: DUP1
000000bd: PUSH4 0x8d3638f4
000000c2: EQ
000000c3: PUSH2 0x0380
000000c6: JUMPI
000000c7: PUSH1 0x00
000000c9: DUP1
000000ca: REVERT
000000cb: JUMPDEST
000000cc: DUP1
000000cd: PUSH4 0x56d5d475
000000d2: GT
000000d3: PUSH2 0x012d
000000d6: JUMPI
000000d7: DUP1
000000d8: PUSH4 0x71a15b38
000000dd: GT
000000de: PUSH2 0x0107
000000e1: JUMPI
000000e2: DUP1
000000e3: PUSH4 0x71a15b38
000000e8: EQ
000000e9: PUSH2 0x02ce
000000ec: JUMPI
000000ed: DUP1
000000ee: PUSH4 0x775313a1
000000f3: EQ
000000f4: PUSH2 0x02ee
000000f7: JUMPI
000000f8: DUP1
000000f9: PUSH4 0x7f5a7c7b
000000fe: EQ
000000ff: PUSH2 0x031b
00000102: JUMPI
00000103: PUSH1 0x00
00000105: DUP1
00000106: REVERT
00000107: JUMPDEST
00000108: DUP1
00000109: PUSH4 0x56d5d475
0000010e: EQ
0000010f: PUSH2 0x0271
00000112: JUMPI
00000113: DUP1
00000114: PUSH4 0x70a08231
00000119: EQ
0000011a: PUSH2 0x0284
0000011d: JUMPI
0000011e: DUP1
0000011f: PUSH4 0x715018a6
00000124: EQ
00000125: PUSH2 0x02b9
00000128: JUMPI
00000129: PUSH1 0x00
0000012b: DUP1
0000012c: REVERT
0000012d: JUMPDEST
0000012e: DUP1
0000012f: PUSH4 0x3dfd3873
00000134: GT
00000135: PUSH2 0x015e
00000138: JUMPI
00000139: DUP1
0000013a: PUSH4 0x3dfd3873
0000013f: EQ
00000140: PUSH2 0x020f
00000143: JUMPI
00000144: DUP1
00000145: PUSH4 0x440df4f4
0000014a: EQ
0000014b: PUSH2 0x022f
0000014e: JUMPI
0000014f: DUP1
00000150: PUSH4 0x49d462ef
00000155: EQ
00000156: PUSH2 0x0251
00000159: JUMPI
0000015a: PUSH1 0x00
0000015c: DUP1
0000015d: REVERT
0000015e: JUMPDEST
0000015f: DUP1
00000160: PUSH4 0x0e72cc06
00000165: EQ
00000166: PUSH2 0x01ba
00000169: JUMPI
0000016a: DUP1
0000016b: PUSH4 0x2ead72f6
00000170: EQ
00000171: PUSH2 0x01dc
00000174: JUMPI
00000175: PUSH1 0x00
00000177: DUP1
00000178: REVERT
00000179: JUMPDEST
0000017a: CALLDATASIZE
0000017b: PUSH2 0x01b5
0000017e: JUMPI
0000017f: PUSH1 0x40
00000181: MLOAD
00000182: CALLVALUE
00000183: DUP2
00000184: MSTORE
00000185: CALLER
00000186: SWAP1
00000187: PUSH32 0x5d8bc849764969eb1bcc6d0a2f55999d0167c1ccec240a4f39cf664ca9c4148e
000001a8: SWAP1
000001a9: PUSH1 0x20
000001ab: ADD
000001ac: PUSH1 0x40
000001ae: MLOAD
000001af: DUP1
000001b0: SWAP2
000001b1: SUB
000001b2: SWAP1
000001b3: LOG2
000001b4: STOP
000001b5: JUMPDEST
000001b6: PUSH1 0x00
000001b8: DUP1
000001b9: REVERT
000001ba: JUMPDEST
000001bb: CALLVALUE
000001bc: DUP1
000001bd: ISZERO
000001be: PUSH2 0x01c6
000001c1: JUMPI
000001c2: PUSH1 0x00
000001c4: DUP1
000001c5: REVERT
000001c6: JUMPDEST
000001c7: POP
000001c8: PUSH2 0x01da
000001cb: PUSH2 0x01d5
000001ce: CALLDATASIZE
000001cf: PUSH1 0x04
000001d1: PUSH2 0x1919
000001d4: JUMP
000001d5: JUMPDEST
000001d6: PUSH2 0x0515
000001d9: JUMP
000001da: JUMPDEST
000001db: STOP
000001dc: JUMPDEST
000001dd: CALLVALUE
000001de: DUP1
000001df: ISZERO
000001e0: PUSH2 0x01e8
000001e3: JUMPI
000001e4: PUSH1 0x00
000001e6: DUP1
000001e7: REVERT
000001e8: JUMPDEST
000001e9: POP
000001ea: PUSH2 0x01fc
000001ed: PUSH2 0x01f7
000001f0: CALLDATASIZE
000001f1: PUSH1 0x04
000001f3: PUSH2 0x1968
000001f6: JUMP
000001f7: JUMPDEST
000001f8: PUSH2 0x0630
000001fb: JUMP
000001fc: JUMPDEST
000001fd: PUSH1 0x40
000001ff: MLOAD
00000200: SWAP1
00000201: DUP2
00000202: MSTORE
00000203: PUSH1 0x20
00000205: ADD
00000206: JUMPDEST
00000207: PUSH1 0x40
00000209: MLOAD
0000020a: DUP1
0000020b: SWAP2
0000020c: SUB
0000020d: SWAP1
0000020e: RETURN
0000020f: JUMPDEST
00000210: CALLVALUE
00000211: DUP1
00000212: ISZERO
00000213: PUSH2 0x021b
00000216: JUMPI
00000217: PUSH1 0x00
00000219: DUP1
0000021a: REVERT
0000021b: JUMPDEST
0000021c: POP
0000021d: PUSH2 0x01da
00000220: PUSH2 0x022a
00000223: CALLDATASIZE
00000224: PUSH1 0x04
00000226: PUSH2 0x1919
00000229: JUMP
0000022a: JUMPDEST
0000022b: PUSH2 0x064f
0000022e: JUMP
0000022f: JUMPDEST
00000230: CALLVALUE
00000231: DUP1
00000232: ISZERO
00000233: PUSH2 0x023b
00000236: JUMPI
00000237: PUSH1 0x00
00000239: DUP1
0000023a: REVERT
0000023b: JUMPDEST
0000023c: POP
0000023d: PUSH2 0x0244
00000240: PUSH2 0x0765
00000243: JUMP
00000244: JUMPDEST
00000245: PUSH1 0x40
00000247: MLOAD
00000248: PUSH2 0x0206
0000024b: SWAP2
0000024c: SWAP1
0000024d: PUSH2 0x1983
00000250: JUMP
00000251: JUMPDEST
00000252: CALLVALUE
00000253: DUP1
00000254: ISZERO
00000255: PUSH2 0x025d
00000258: JUMPI
00000259: PUSH1 0x00
0000025b: DUP1
0000025c: REVERT
0000025d: JUMPDEST
0000025e: POP
0000025f: PUSH2 0x01da
00000262: PUSH2 0x026c
00000265: CALLDATASIZE
00000266: PUSH1 0x04
00000268: PUSH2 0x19cd
0000026b: JUMP
0000026c: JUMPDEST
0000026d: PUSH2 0x0776
00000270: JUMP
00000271: JUMPDEST
00000272: PUSH2 0x01da
00000275: PUSH2 0x027f
00000278: CALLDATASIZE
00000279: PUSH1 0x04
0000027b: PUSH2 0x19f7
0000027e: JUMP
0000027f: JUMPDEST
00000280: PUSH2 0x079c
00000283: JUMP
00000284: JUMPDEST
00000285: CALLVALUE
00000286: DUP1
00000287: ISZERO
00000288: PUSH2 0x0290
0000028b: JUMPI
0000028c: PUSH1 0x00
0000028e: DUP1
0000028f: REVERT
00000290: JUMPDEST
00000291: POP
00000292: PUSH2 0x01fc
00000295: PUSH2 0x029f
00000298: CALLDATASIZE
00000299: PUSH1 0x04
0000029b: PUSH2 0x1919
0000029e: JUMP
0000029f: JUMPDEST
000002a0: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
000002b5: AND
000002b6: BALANCE
000002b7: SWAP1
000002b8: JUMP
000002b9: JUMPDEST
000002ba: CALLVALUE
000002bb: DUP1
000002bc: ISZERO
000002bd: PUSH2 0x02c5
000002c0: JUMPI
000002c1: PUSH1 0x00
000002c3: DUP1
000002c4: REVERT
000002c5: JUMPDEST
000002c6: POP
000002c7: PUSH2 0x01da
000002ca: PUSH2 0x0910
000002cd: JUMP
000002ce: JUMPDEST
000002cf: CALLVALUE
000002d0: DUP1
000002d1: ISZERO
000002d2: PUSH2 0x02da
000002d5: JUMPI
000002d6: PUSH1 0x00
000002d8: DUP1
000002d9: REVERT
000002da: JUMPDEST
000002db: POP
000002dc: PUSH2 0x01da
000002df: PUSH2 0x02e9
000002e2: CALLDATASIZE
000002e3: PUSH1 0x04
000002e5: PUSH2 0x1ac3
000002e8: JUMP
000002e9: JUMPDEST
000002ea: PUSH2 0x0924
000002ed: JUMP
000002ee: JUMPDEST
000002ef: CALLVALUE
000002f0: DUP1
000002f1: ISZERO
000002f2: PUSH2 0x02fa
000002f5: JUMPI
000002f6: PUSH1 0x00
000002f8: DUP1
000002f9: REVERT
000002fa: JUMPDEST
000002fb: POP
000002fc: PUSH2 0x01fc
000002ff: PUSH2 0x0309
00000302: CALLDATASIZE
00000303: PUSH1 0x04
00000305: PUSH2 0x1968
00000308: JUMP
00000309: JUMPDEST
0000030a: PUSH1 0xca
0000030c: PUSH1 0x20
0000030e: MSTORE
0000030f: PUSH1 0x00
00000311: SWAP1
00000312: DUP2
00000313: MSTORE
00000314: PUSH1 0x40
00000316: SWAP1
00000317: KECCAK256
00000318: SLOAD
00000319: DUP2
0000031a: JUMP
0000031b: JUMPDEST
0000031c: CALLVALUE
0000031d: DUP1
0000031e: ISZERO
0000031f: PUSH2 0x0327
00000322: JUMPI
00000323: PUSH1 0x00
00000325: DUP1
00000326: REVERT
00000327: JUMPDEST
00000328: POP
00000329: PUSH1 0x65
0000032b: SLOAD
0000032c: PUSH2 0x0348
0000032f: SWAP1
00000330: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
00000345: AND
00000346: DUP2
00000347: JUMP
00000348: JUMPDEST
00000349: PUSH1 0x40
0000034b: MLOAD
0000034c: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
00000361: SWAP1
00000362: SWAP2
00000363: AND
00000364: DUP2
00000365: MSTORE
00000366: PUSH1 0x20
00000368: ADD
00000369: PUSH2 0x0206
0000036c: JUMP
0000036d: JUMPDEST
0000036e: PUSH2 0x01fc
00000371: PUSH2 0x037b
00000374: CALLDATASIZE
00000375: PUSH1 0x04
00000377: PUSH2 0x1b05
0000037a: JUMP
0000037b: JUMPDEST
0000037c: PUSH2 0x097f
0000037f: JUMP
00000380: JUMPDEST
00000381: CALLVALUE
00000382: DUP1
00000383: ISZERO
00000384: PUSH2 0x038c
00000387: JUMPI
00000388: PUSH1 0x00
0000038a: DUP1
0000038b: REVERT
0000038c: JUMPDEST
0000038d: POP
0000038e: PUSH2 0x03b4
00000391: PUSH32 0x0000000000000000000000000000000000000000000000000000000000000001
000003b2: DUP2
000003b3: JUMP
000003b4: JUMPDEST
000003b5: PUSH1 0x40
000003b7: MLOAD
000003b8: PUSH4 0xffffffff
000003bd: SWAP1
000003be: SWAP2
000003bf: AND
000003c0: DUP2
000003c1: MSTORE
000003c2: PUSH1 0x20
000003c4: ADD
000003c5: PUSH2 0x0206
000003c8: JUMP
000003c9: JUMPDEST
000003ca: CALLVALUE
000003cb: DUP1
000003cc: ISZERO
000003cd: PUSH2 0x03d5
000003d0: JUMPI
000003d1: PUSH1 0x00
000003d3: DUP1
000003d4: REVERT
000003d5: JUMPDEST
000003d6: POP
000003d7: PUSH1 0x33
000003d9: SLOAD
000003da: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
000003ef: AND
000003f0: PUSH2 0x0348
000003f3: JUMP
000003f4: JUMPDEST
000003f5: CALLVALUE
000003f6: DUP1
000003f7: ISZERO
000003f8: PUSH2 0x0400
000003fb: JUMPI
000003fc: PUSH1 0x00
000003fe: DUP1
000003ff: REVERT
00000400: JUMPDEST
00000401: POP
00000402: PUSH2 0x01da
00000405: PUSH2 0x040f
00000408: CALLDATASIZE
00000409: PUSH1 0x04
0000040b: PUSH2 0x1b38
0000040e: JUMP
0000040f: JUMPDEST
00000410: PUSH2 0x0a0e
00000413: JUMP
00000414: JUMPDEST
00000415: CALLVALUE
00000416: DUP1
00000417: ISZERO
00000418: PUSH2 0x0420
0000041b: JUMPI
0000041c: PUSH1 0x00
0000041e: DUP1
0000041f: REVERT
00000420: JUMPDEST
00000421: POP
00000422: PUSH2 0x01da
00000425: PUSH2 0x042f
00000428: CALLDATASIZE
00000429: PUSH1 0x04
0000042b: PUSH2 0x19cd
0000042e: JUMP
0000042f: JUMPDEST
00000430: PUSH2 0x0a98
00000433: JUMP
00000434: JUMPDEST
00000435: CALLVALUE
00000436: DUP1
00000437: ISZERO
00000438: PUSH2 0x0440
0000043b: JUMPI
0000043c: PUSH1 0x00
0000043e: DUP1
0000043f: REVERT
00000440: JUMPDEST
00000441: POP
00000442: PUSH2 0x0348
00000445: PUSH32 0x000000000000000000000000c005dc82818d67af737725bd4bf75435d065d239
00000466: DUP2
00000467: JUMP
00000468: JUMPDEST
00000469: CALLVALUE
0000046a: DUP1
0000046b: ISZERO
0000046c: PUSH2 0x0474
0000046f: JUMPI
00000470: PUSH1 0x00
00000472: DUP1
00000473: REVERT
00000474: JUMPDEST
00000475: POP
00000476: PUSH1 0x66
00000478: SLOAD
00000479: PUSH2 0x0348
0000047c: SWAP1
0000047d: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
00000492: AND
00000493: DUP2
00000494: JUMP
00000495: JUMPDEST
00000496: CALLVALUE
00000497: DUP1
00000498: ISZERO
00000499: PUSH2 0x04a1
0000049c: JUMPI
0000049d: PUSH1 0x00
0000049f: DUP1
000004a0: REVERT
000004a1: JUMPDEST
000004a2: POP
000004a3: PUSH2 0x01da
000004a6: PUSH2 0x04b0
000004a9: CALLDATASIZE
000004aa: PUSH1 0x04
000004ac: PUSH2 0x1bad
000004af: JUMP
000004b0: JUMPDEST
000004b1: PUSH2 0x0aaa
000004b4: JUMP
000004b5: JUMPDEST
000004b6: CALLVALUE
000004b7: DUP1
000004b8: ISZERO
000004b9: PUSH2 0x04c1
000004bc: JUMPI
000004bd: PUSH1 0x00
000004bf: DUP1
000004c0: REVERT
000004c1: JUMPDEST
000004c2: POP
000004c3: PUSH2 0x01da
000004c6: PUSH2 0x04d0
000004c9: CALLDATASIZE
000004ca: PUSH1 0x04
000004cc: PUSH2 0x1968
000004cf: JUMP
000004d0: JUMPDEST
000004d1: PUSH2 0x0b89
000004d4: JUMP
000004d5: JUMPDEST
000004d6: CALLVALUE
000004d7: DUP1
000004d8: ISZERO
000004d9: PUSH2 0x04e1
000004dc: JUMPI
000004dd: PUSH1 0x00
000004df: DUP1
000004e0: REVERT
000004e1: JUMPDEST
000004e2: POP
000004e3: PUSH2 0x01fc
000004e6: PUSH2 0x04f0
000004e9: CALLDATASIZE
000004ea: PUSH1 0x04
000004ec: PUSH2 0x1968
000004ef: JUMP
000004f0: JUMPDEST
000004f1: PUSH2 0x0b9d
000004f4: JUMP
000004f5: JUMPDEST
000004f6: CALLVALUE
000004f7: DUP1
000004f8: ISZERO
000004f9: PUSH2 0x0501
000004fc: JUMPI
000004fd: PUSH1 0x00
000004ff: DUP1
00000500: REVERT
00000501: JUMPDEST
00000502: POP
00000503: PUSH2 0x01da
00000506: PUSH2 0x0510
00000509: CALLDATASIZE
0000050a: PUSH1 0x04
0000050c: PUSH2 0x1919
0000050f: JUMP
00000510: JUMPDEST
00000511: PUSH2 0x0bbe
00000514: JUMP
00000515: JUMPDEST
00000516: DUP1
00000517: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
0000052c: DUP2
0000052d: AND
0000052e: EXTCODESIZE
0000052f: ISZERO
00000530: ISZERO
00000531: DUP1
00000532: PUSH2 0x054f
00000535: JUMPI
00000536: POP
00000537: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
0000054c: DUP2
0000054d: AND
0000054e: ISZERO
0000054f: JUMPDEST
00000550: PUSH2 0x05e0
00000553: JUMPI
00000554: PUSH1 0x40
00000556: MLOAD
00000557: PUSH32 0x08c379a000000000000000000000000000000000000000000000000000000000
00000578: DUP2
00000579: MSTORE
0000057a: PUSH1 0x20
0000057c: PUSH1 0x04
0000057e: DUP3
0000057f: ADD
00000580: MSTORE
00000581: PUSH1 0x27
00000583: PUSH1 0x24
00000585: DUP3
00000586: ADD
00000587: MSTORE
00000588: PUSH32 0x4d61696c626f78436c69656e743a20696e76616c696420636f6e747261637420
000005a9: PUSH1 0x44
000005ab: DUP3
000005ac: ADD
000005ad: MSTORE
000005ae: PUSH32 0x73657474696e6700000000000000000000000000000000000000000000000000
000005cf: PUSH1 0x64
000005d1: DUP3
000005d2: ADD
000005d3: MSTORE
000005d4: PUSH1 0x84
000005d6: ADD
000005d7: JUMPDEST
000005d8: PUSH1 0x40
000005da: MLOAD
000005db: DUP1
000005dc: SWAP2
000005dd: SUB
000005de: SWAP1
000005df: REVERT
000005e0: JUMPDEST
000005e1: PUSH2 0x05e8
000005e4: PUSH2 0x0c72
000005e7: JUMP
000005e8: JUMPDEST
000005e9: POP
000005ea: PUSH1 0x66
000005ec: DUP1
000005ed: SLOAD
000005ee: PUSH32 0xffffffffffffffffffffffff0000000000000000000000000000000000000000
0000060f: AND
00000610: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
00000625: SWAP3
00000626: SWAP1
00000627: SWAP3
00000628: AND
00000629: SWAP2
0000062a: SWAP1
0000062b: SWAP2
0000062c: OR
0000062d: SWAP1
0000062e: SSTORE
0000062f: JUMP
00000630: JUMPDEST
00000631: PUSH1 0x00
00000633: DUP1
00000634: PUSH2 0x0647
00000637: PUSH1 0x97
00000639: PUSH4 0xffffffff
0000063e: DUP1
0000063f: DUP7
00000640: AND
00000641: SWAP1
00000642: PUSH2 0x0cf3
00000645: AND
00000646: JUMP
00000647: JUMPDEST
00000648: SWAP5
00000649: SWAP4
0000064a: POP
0000064b: POP
0000064c: POP
0000064d: POP
0000064e: JUMP
0000064f: JUMPDEST
00000650: DUP1
00000651: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
00000666: DUP2
00000667: AND
00000668: EXTCODESIZE
00000669: ISZERO
0000066a: ISZERO
0000066b: DUP1
0000066c: PUSH2 0x0689
0000066f: JUMPI
00000670: POP
00000671: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
00000686: DUP2
00000687: AND
00000688: ISZERO
00000689: JUMPDEST
0000068a: PUSH2 0x0715
0000068d: JUMPI
0000068e: PUSH1 0x40
00000690: MLOAD
00000691: PUSH32 0x08c379a000000000000000000000000000000000000000000000000000000000
000006b2: DUP2
000006b3: MSTORE
000006b4: PUSH1 0x20
000006b6: PUSH1 0x04
000006b8: DUP3
000006b9: ADD
000006ba: MSTORE
000006bb: PUSH1 0x27
000006bd: PUSH1 0x24
000006bf: DUP3
000006c0: ADD
000006c1: MSTORE
000006c2: PUSH32 0x4d61696c626f78436c69656e743a20696e76616c696420636f6e747261637420
000006e3: PUSH1 0x44
000006e5: DUP3
000006e6: ADD
000006e7: MSTORE
000006e8: PUSH32 0x73657474696e6700000000000000000000000000000000000000000000000000
00000709: PUSH1 0x64
0000070b: DUP3
0000070c: ADD
0000070d: MSTORE
0000070e: PUSH1 0x84
00000710: ADD
00000711: PUSH2 0x05d7
00000714: JUMP
00000715: JUMPDEST
00000716: PUSH2 0x071d
00000719: PUSH2 0x0c72
0000071c: JUMP
0000071d: JUMPDEST
0000071e: POP
0000071f: PUSH1 0x65
00000721: DUP1
00000722: SLOAD
00000723: PUSH32 0xffffffffffffffffffffffff0000000000000000000000000000000000000000
00000744: AND
00000745: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
0000075a: SWAP3
0000075b: SWAP1
0000075c: SWAP3
0000075d: AND
0000075e: SWAP2
0000075f: SWAP1
00000760: SWAP2
00000761: OR
00000762: SWAP1
00000763: SSTORE
00000764: JUMP
00000765: JUMPDEST
00000766: PUSH1 0x60
00000768: PUSH2 0x0771
0000076b: PUSH1 0x97
0000076d: PUSH2 0x0d0c
00000770: JUMP
00000771: JUMPDEST
00000772: SWAP1
00000773: POP
00000774: SWAP1
00000775: JUMP
00000776: JUMPDEST
00000777: PUSH2 0x077e
0000077a: PUSH2 0x0c72
0000077d: JUMP
0000077e: JUMPDEST
0000077f: PUSH4 0xffffffff
00000784: SWAP2
00000785: SWAP1
00000786: SWAP2
00000787: AND
00000788: PUSH1 0x00
0000078a: SWAP1
0000078b: DUP2
0000078c: MSTORE
0000078d: PUSH1 0xca
0000078f: PUSH1 0x20
00000791: MSTORE
00000792: PUSH1 0x40
00000794: SWAP1
00000795: KECCAK256
00000796: SSTORE
00000797: JUMP
00000798: JUMPDEST
00000799: POP
0000079a: POP
0000079b: JUMP
0000079c: JUMPDEST
0000079d: CALLER
0000079e: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
000007b3: PUSH32 0x000000000000000000000000c005dc82818d67af737725bd4bf75435d065d239
000007d4: AND
000007d5: EQ
000007d6: PUSH2 0x0861
000007d9: JUMPI
000007da: PUSH1 0x40
000007dc: MLOAD
000007dd: PUSH32 0x08c379a000000000000000000000000000000000000000000000000000000000
000007fe: DUP2
000007ff: MSTORE
00000800: PUSH1 0x20
00000802: PUSH1 0x04
00000804: DUP3
00000805: ADD
00000806: MSTORE
00000807: PUSH1 0x21
00000809: PUSH1 0x24
0000080b: DUP3
0000080c: ADD
0000080d: MSTORE
0000080e: PUSH32 0x4d61696c626f78436c69656e743a2073656e646572206e6f74206d61696c626f
0000082f: PUSH1 0x44
00000831: DUP3
00000832: ADD
00000833: MSTORE
00000834: PUSH32 0x7800000000000000000000000000000000000000000000000000000000000000
00000855: PUSH1 0x64
00000857: DUP3
00000858: ADD
00000859: MSTORE
0000085a: PUSH1 0x84
0000085c: ADD
0000085d: PUSH2 0x05d7
00000860: JUMP
00000861: JUMPDEST
00000862: PUSH1 0x00
00000864: PUSH2 0x086c
00000867: DUP6
00000868: PUSH2 0x0dc7
0000086b: JUMP
0000086c: JUMPDEST
0000086d: SWAP1
0000086e: POP
0000086f: DUP4
00000870: DUP2
00000871: EQ
00000872: PUSH2 0x08fd
00000875: JUMPI
00000876: PUSH1 0x40
00000878: MLOAD
00000879: PUSH32 0x08c379a000000000000000000000000000000000000000000000000000000000
0000089a: DUP2
0000089b: MSTORE
0000089c: PUSH1 0x20
0000089e: PUSH1 0x04
000008a0: DUP3
000008a1: ADD
000008a2: MSTORE
000008a3: PUSH1 0x25
000008a5: PUSH1 0x24
000008a7: DUP3
000008a8: ADD
000008a9: MSTORE
000008aa: PUSH32 0x456e726f6c6c656420726f7574657220646f6573206e6f74206d617463682073
000008cb: PUSH1 0x44
000008cd: DUP3
000008ce: ADD
000008cf: MSTORE
000008d0: PUSH32 0x656e646572000000000000000000000000000000000000000000000000000000
000008f1: PUSH1 0x64
000008f3: DUP3
000008f4: ADD
000008f5: MSTORE
000008f6: PUSH1 0x84
000008f8: ADD
000008f9: PUSH2 0x05d7
000008fc: JUMP
000008fd: JUMPDEST
000008fe: PUSH2 0x0909
00000901: DUP6
00000902: DUP6
00000903: DUP6
00000904: DUP6
00000905: PUSH2 0x0e2d
00000908: JUMP
00000909: JUMPDEST
0000090a: POP
0000090b: POP
0000090c: POP
0000090d: POP
0000090e: POP
0000090f: JUMP
00000910: JUMPDEST
00000911: PUSH2 0x0918
00000914: PUSH2 0x0c72
00000917: JUMP
00000918: JUMPDEST
00000919: PUSH2 0x0922
0000091c: PUSH1 0x00
0000091e: PUSH2 0x0eb7
00000921: JUMP
00000922: JUMPDEST
00000923: JUMP
00000924: JUMPDEST
00000925: PUSH2 0x092c
00000928: PUSH2 0x0c72
0000092b: JUMP
0000092c: JUMPDEST
0000092d: DUP1
0000092e: PUSH1 0x00
00000930: JUMPDEST
00000931: DUP2
00000932: DUP2
00000933: LT
00000934: ISZERO
00000935: PUSH2 0x0979
00000938: JUMPI
00000939: PUSH2 0x0967
0000093c: DUP5
0000093d: DUP5
0000093e: DUP4
0000093f: DUP2
00000940: DUP2
00000941: LT
00000942: PUSH2 0x094d
00000945: JUMPI
00000946: PUSH2 0x094d
00000949: PUSH2 0x1c19
0000094c: JUMP
0000094d: JUMPDEST
0000094e: SWAP1
0000094f: POP
00000950: PUSH1 0x20
00000952: MUL
00000953: ADD
00000954: PUSH1 0x20
00000956: DUP2
00000957: ADD
00000958: SWAP1
00000959: PUSH2 0x0962
0000095c: SWAP2
0000095d: SWAP1
0000095e: PUSH2 0x1968
00000961: JUMP
00000962: JUMPDEST
00000963: PUSH2 0x0f2e
00000966: JUMP
00000967: JUMPDEST
00000968: PUSH2 0x0972
0000096b: PUSH1 0x01
0000096d: DUP3
0000096e: PUSH2 0x1c77
00000971: JUMP
00000972: JUMPDEST
00000973: SWAP1
00000974: POP
00000975: PUSH2 0x0930
00000978: JUMP
00000979: JUMPDEST
0000097a: POP
0000097b: POP
0000097c: POP
0000097d: POP
0000097e: JUMP
0000097f: JUMPDEST
00000980: PUSH1 0x00
00000982: DUP2
00000983: CALLVALUE
00000984: LT
00000985: ISZERO
00000986: PUSH2 0x09eb
00000989: JUMPI
0000098a: PUSH1 0x40
0000098c: MLOAD
0000098d: PUSH32 0x08c379a000000000000000000000000000000000000000000000000000000000
000009ae: DUP2
000009af: MSTORE
000009b0: PUSH1 0x20
000009b2: PUSH1 0x04
000009b4: DUP3
000009b5: ADD
000009b6: DUP2
000009b7: SWAP1
000009b8: MSTORE
000009b9: PUSH1 0x24
000009bb: DUP3
000009bc: ADD
000009bd: MSTORE
000009be: PUSH32 0x4e61746976653a20616d6f756e742065786365656473206d73672e76616c7565
000009df: PUSH1 0x44
000009e1: DUP3
000009e2: ADD
000009e3: MSTORE
000009e4: PUSH1 0x64
000009e6: ADD
000009e7: PUSH2 0x05d7
000009ea: JUMP
000009eb: JUMPDEST
000009ec: PUSH1 0x00
000009ee: PUSH2 0x09f7
000009f1: DUP4
000009f2: CALLVALUE
000009f3: PUSH2 0x1c8a
000009f6: JUMP
000009f7: JUMPDEST
000009f8: SWAP1
000009f9: POP
000009fa: PUSH2 0x0a05
000009fd: DUP6
000009fe: DUP6
000009ff: DUP6
00000a00: DUP5
00000a01: PUSH2 0x0f83
00000a04: JUMP
00000a05: JUMPDEST
00000a06: SWAP6
00000a07: SWAP5
00000a08: POP
00000a09: POP
00000a0a: POP
00000a0b: POP
00000a0c: POP
00000a0d: JUMP
00000a0e: JUMPDEST
00000a0f: PUSH2 0x0a16
00000a12: PUSH2 0x0c72
00000a15: JUMP
00000a16: JUMPDEST
00000a17: PUSH1 0x00
00000a19: JUMPDEST
00000a1a: DUP2
00000a1b: DUP2
00000a1c: LT
00000a1d: ISZERO
00000a1e: PUSH2 0x0a93
00000a21: JUMPI
00000a22: PUSH2 0x0a81
00000a25: DUP4
00000a26: DUP4
00000a27: DUP4
00000a28: DUP2
00000a29: DUP2
00000a2a: LT
00000a2b: PUSH2 0x0a36
00000a2e: JUMPI
00000a2f: PUSH2 0x0a36
00000a32: PUSH2 0x1c19
00000a35: JUMP
00000a36: JUMPDEST
00000a37: PUSH2 0x0a4c
00000a3a: SWAP3
00000a3b: PUSH1 0x20
00000a3d: PUSH1 0x40
00000a3f: SWAP1
00000a40: SWAP3
00000a41: MUL
00000a42: ADD
00000a43: SWAP1
00000a44: DUP2
00000a45: ADD
00000a46: SWAP2
00000a47: POP
00000a48: PUSH2 0x1968
00000a4b: JUMP
00000a4c: JUMPDEST
00000a4d: DUP5
00000a4e: DUP5
00000a4f: DUP5
00000a50: DUP2
00000a51: DUP2
00000a52: LT
00000a53: PUSH2 0x0a5e
00000a56: JUMPI
00000a57: PUSH2 0x0a5e
00000a5a: PUSH2 0x1c19
00000a5d: JUMP
00000a5e: JUMPDEST
00000a5f: SWAP1
00000a60: POP
00000a61: PUSH1 0x40
00000a63: MUL
00000a64: ADD
00000a65: PUSH1 0x20
00000a67: ADD
00000a68: CALLDATALOAD
00000a69: PUSH4 0xffffffff
00000a6e: SWAP1
00000a6f: SWAP2
00000a70: AND
00000a71: PUSH1 0x00
00000a73: SWAP1
00000a74: DUP2
00000a75: MSTORE
00000a76: PUSH1 0xca
00000a78: PUSH1 0x20
00000a7a: MSTORE
00000a7b: PUSH1 0x40
00000a7d: SWAP1
00000a7e: KECCAK256
00000a7f: SSTORE
00000a80: JUMP
00000a81: JUMPDEST
00000a82: PUSH2 0x0a8c
00000a85: PUSH1 0x01
00000a87: DUP3
00000a88: PUSH2 0x1c77
00000a8b: JUMP
00000a8c: JUMPDEST
00000a8d: SWAP1
00000a8e: POP
00000a8f: PUSH2 0x0a19
00000a92: JUMP
00000a93: JUMPDEST
00000a94: POP
00000a95: POP
00000a96: POP
00000a97: JUMP
00000a98: JUMPDEST
00000a99: PUSH2 0x0aa0
00000a9c: PUSH2 0x0c72
00000a9f: JUMP
00000aa0: JUMPDEST
00000aa1: PUSH2 0x0798
00000aa4: DUP3
00000aa5: DUP3
00000aa6: PUSH2 0x0ffe
00000aa9: JUMP
00000aaa: JUMPDEST
00000aab: PUSH2 0x0ab2
00000aae: PUSH2 0x0c72
00000ab1: JUMP
00000ab2: JUMPDEST
00000ab3: DUP3
00000ab4: DUP2
00000ab5: EQ
00000ab6: PUSH2 0x0b1b
00000ab9: JUMPI
00000aba: PUSH1 0x40
00000abc: MLOAD
00000abd: PUSH32 0x08c379a000000000000000000000000000000000000000000000000000000000
00000ade: DUP2
00000adf: MSTORE
00000ae0: PUSH1 0x20
00000ae2: PUSH1 0x04
00000ae4: DUP3
00000ae5: ADD
00000ae6: MSTORE
00000ae7: PUSH1 0x07
00000ae9: PUSH1 0x24
00000aeb: DUP3
00000aec: ADD
00000aed: MSTORE
00000aee: PUSH32 0x216c656e67746800000000000000000000000000000000000000000000000000
00000b0f: PUSH1 0x44
00000b11: DUP3
00000b12: ADD
00000b13: MSTORE
00000b14: PUSH1 0x64
00000b16: ADD
00000b17: PUSH2 0x05d7
00000b1a: JUMP
00000b1b: JUMPDEST
00000b1c: DUP3
00000b1d: PUSH1 0x00
00000b1f: JUMPDEST
00000b20: DUP2
00000b21: DUP2
00000b22: LT
00000b23: ISZERO
00000b24: PUSH2 0x0b81
00000b27: JUMPI
00000b28: PUSH2 0x0b6f
00000b2b: DUP7
00000b2c: DUP7
00000b2d: DUP4
00000b2e: DUP2
00000b2f: DUP2
00000b30: LT
00000b31: PUSH2 0x0b3c
00000b34: JUMPI
00000b35: PUSH2 0x0b3c
00000b38: PUSH2 0x1c19
00000b3b: JUMP
00000b3c: JUMPDEST
00000b3d: SWAP1
00000b3e: POP
00000b3f: PUSH1 0x20
00000b41: MUL
00000b42: ADD
00000b43: PUSH1 0x20
00000b45: DUP2
00000b46: ADD
00000b47: SWAP1
00000b48: PUSH2 0x0b51
00000b4b: SWAP2
00000b4c: SWAP1
00000b4d: PUSH2 0x1968
00000b50: JUMP
00000b51: JUMPDEST
00000b52: DUP6
00000b53: DUP6
00000b54: DUP5
00000b55: DUP2
00000b56: DUP2
00000b57: LT
00000b58: PUSH2 0x0b63
00000b5b: JUMPI
00000b5c: PUSH2 0x0b63
00000b5f: PUSH2 0x1c19
00000b62: JUMP
00000b63: JUMPDEST
00000b64: SWAP1
00000b65: POP
00000b66: PUSH1 0x20
00000b68: MUL
00000b69: ADD
00000b6a: CALLDATALOAD
00000b6b: PUSH2 0x0ffe
00000b6e: JUMP
00000b6f: JUMPDEST
00000b70: PUSH2 0x0b7a
00000b73: PUSH1 0x01
00000b75: DUP3
00000b76: PUSH2 0x1c77
00000b79: JUMP
00000b7a: JUMPDEST
00000b7b: SWAP1
00000b7c: POP
00000b7d: PUSH2 0x0b1f
00000b80: JUMP
00000b81: JUMPDEST
00000b82: POP
00000b83: POP
00000b84: POP
00000b85: POP
00000b86: POP
00000b87: POP
00000b88: JUMP
00000b89: JUMPDEST
00000b8a: PUSH2 0x0b91
00000b8d: PUSH2 0x0c72
00000b90: JUMP
00000b91: JUMPDEST
00000b92: PUSH2 0x0b9a
00000b95: DUP2
00000b96: PUSH2 0x0f2e
00000b99: JUMP
00000b9a: JUMPDEST
00000b9b: POP
00000b9c: JUMP
00000b9d: JUMPDEST
00000b9e: PUSH1 0x00
00000ba0: PUSH2 0x0bb8
00000ba3: DUP3
00000ba4: PUSH1 0x40
00000ba6: MLOAD
00000ba7: DUP1
00000ba8: PUSH1 0x20
00000baa: ADD
00000bab: PUSH1 0x40
00000bad: MSTORE
00000bae: DUP1
00000baf: PUSH1 0x00
00000bb1: DUP2
00000bb2: MSTORE
00000bb3: POP
00000bb4: PUSH2 0x1014
00000bb7: JUMP
00000bb8: JUMPDEST
00000bb9: SWAP3
00000bba: SWAP2
00000bbb: POP
00000bbc: POP
00000bbd: JUMP
00000bbe: JUMPDEST
00000bbf: PUSH2 0x0bc6
00000bc2: PUSH2 0x0c72
00000bc5: JUMP
00000bc6: JUMPDEST
00000bc7: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
00000bdc: DUP2
00000bdd: AND
00000bde: PUSH2 0x0c69
00000be1: JUMPI
00000be2: PUSH1 0x40
00000be4: MLOAD
00000be5: PUSH32 0x08c379a000000000000000000000000000000000000000000000000000000000
00000c06: DUP2
00000c07: MSTORE
00000c08: PUSH1 0x20
00000c0a: PUSH1 0x04
00000c0c: DUP3
00000c0d: ADD
00000c0e: MSTORE
00000c0f: PUSH1 0x26
00000c11: PUSH1 0x24
00000c13: DUP3
00000c14: ADD
00000c15: MSTORE
00000c16: PUSH32 0x4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061
00000c37: PUSH1 0x44
00000c39: DUP3
00000c3a: ADD
00000c3b: MSTORE
00000c3c: PUSH32 0x6464726573730000000000000000000000000000000000000000000000000000
00000c5d: PUSH1 0x64
00000c5f: DUP3
00000c60: ADD
00000c61: MSTORE
00000c62: PUSH1 0x84
00000c64: ADD
00000c65: PUSH2 0x05d7
00000c68: JUMP
00000c69: JUMPDEST
00000c6a: PUSH2 0x0b9a
00000c6d: DUP2
00000c6e: PUSH2 0x0eb7
00000c71: JUMP
00000c72: JUMPDEST
00000c73: PUSH1 0x33
00000c75: SLOAD
00000c76: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
00000c8b: AND
00000c8c: CALLER
00000c8d: EQ
00000c8e: PUSH2 0x0922
00000c91: JUMPI
00000c92: PUSH1 0x40
00000c94: MLOAD
00000c95: PUSH32 0x08c379a000000000000000000000000000000000000000000000000000000000
00000cb6: DUP2
00000cb7: MSTORE
00000cb8: PUSH1 0x20
00000cba: PUSH1 0x04
00000cbc: DUP3
00000cbd: ADD
00000cbe: DUP2
00000cbf: SWAP1
00000cc0: MSTORE
00000cc1: PUSH1 0x24
00000cc3: DUP3
00000cc4: ADD
00000cc5: MSTORE
00000cc6: PUSH32 0x4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572
00000ce7: PUSH1 0x44
00000ce9: DUP3
00000cea: ADD
00000ceb: MSTORE
00000cec: PUSH1 0x64
00000cee: ADD
00000cef: PUSH2 0x05d7
00000cf2: JUMP
00000cf3: JUMPDEST
00000cf4: PUSH1 0x00
00000cf6: DUP1
00000cf7: PUSH2 0x0d00
00000cfa: DUP5
00000cfb: DUP5
00000cfc: PUSH2 0x102d
00000cff: JUMP
00000d00: JUMPDEST
00000d01: SWAP2
00000d02: POP
00000d03: SWAP2
00000d04: POP
00000d05: JUMPDEST
00000d06: SWAP3
00000d07: POP
00000d08: SWAP3
00000d09: SWAP1
00000d0a: POP
00000d0b: JUMP
00000d0c: JUMPDEST
00000d0d: PUSH1 0x60
00000d0f: PUSH1 0x00
00000d11: PUSH2 0x0d19
00000d14: DUP4
00000d15: PUSH2 0x1067
00000d18: JUMP
00000d19: JUMPDEST
00000d1a: SWAP1
00000d1b: POP
00000d1c: DUP1
00000d1d: MLOAD
00000d1e: PUSH8 0xffffffffffffffff
00000d27: DUP2
00000d28: GT
00000d29: ISZERO
00000d2a: PUSH2 0x0d35
00000d2d: JUMPI
00000d2e: PUSH2 0x0d35
00000d31: PUSH2 0x1c9d
00000d34: JUMP
00000d35: JUMPDEST
00000d36: PUSH1 0x40
00000d38: MLOAD
00000d39: SWAP1
00000d3a: DUP1
00000d3b: DUP3
00000d3c: MSTORE
00000d3d: DUP1
00000d3e: PUSH1 0x20
00000d40: MUL
00000d41: PUSH1 0x20
00000d43: ADD
00000d44: DUP3
00000d45: ADD
00000d46: PUSH1 0x40
00000d48: MSTORE
00000d49: DUP1
00000d4a: ISZERO
00000d4b: PUSH2 0x0d5e
00000d4e: JUMPI
00000d4f: DUP2
00000d50: PUSH1 0x20
00000d52: ADD
00000d53: PUSH1 0x20
00000d55: DUP3
00000d56: MUL
00000d57: DUP1
00000d58: CALLDATASIZE
00000d59: DUP4
00000d5a: CALLDATACOPY
00000d5b: ADD
00000d5c: SWAP1
00000d5d: POP
00000d5e: JUMPDEST
00000d5f: POP
00000d60: SWAP2
00000d61: POP
00000d62: PUSH1 0x00
00000d64: JUMPDEST
00000d65: DUP2
00000d66: MLOAD
00000d67: DUP2
00000d68: LT
00000d69: ISZERO
00000d6a: PUSH2 0x0dc0
00000d6d: JUMPI
00000d6e: DUP2
00000d6f: DUP2
00000d70: DUP2
00000d71: MLOAD
00000d72: DUP2
00000d73: LT
00000d74: PUSH2 0x0d7f
00000d77: JUMPI
00000d78: PUSH2 0x0d7f
00000d7b: PUSH2 0x1c19
00000d7e: JUMP
00000d7f: JUMPDEST
00000d80: PUSH1 0x20
00000d82: MUL
00000d83: PUSH1 0x20
00000d85: ADD
00000d86: ADD
00000d87: MLOAD
00000d88: DUP4
00000d89: DUP3
00000d8a: DUP2
00000d8b: MLOAD
00000d8c: DUP2
00000d8d: LT
00000d8e: PUSH2 0x0d99
00000d91: JUMPI
00000d92: PUSH2 0x0d99
00000d95: PUSH2 0x1c19
00000d98: JUMP
00000d99: JUMPDEST
00000d9a: PUSH4 0xffffffff
00000d9f: SWAP1
00000da0: SWAP3
00000da1: AND
00000da2: PUSH1 0x20
00000da4: SWAP3
00000da5: DUP4
00000da6: MUL
00000da7: SWAP2
00000da8: SWAP1
00000da9: SWAP2
00000daa: ADD
00000dab: SWAP1
00000dac: SWAP2
00000dad: ADD
00000dae: MSTORE
00000daf: DUP1
00000db0: PUSH2 0x0db8
00000db3: DUP2
00000db4: PUSH2 0x1ccc
00000db7: JUMP
00000db8: JUMPDEST
00000db9: SWAP2
00000dba: POP
00000dbb: POP
00000dbc: PUSH2 0x0d64
00000dbf: JUMP
00000dc0: JUMPDEST
00000dc1: POP
00000dc2: POP
00000dc3: SWAP2
00000dc4: SWAP1
00000dc5: POP
00000dc6: JUMP
00000dc7: JUMPDEST
00000dc8: PUSH1 0x00
00000dca: DUP1
00000dcb: DUP1
00000dcc: PUSH2 0x0ddf
00000dcf: PUSH1 0x97
00000dd1: PUSH4 0xffffffff
00000dd6: DUP1
00000dd7: DUP8
00000dd8: AND
00000dd9: SWAP1
00000dda: PUSH2 0x0cf3
00000ddd: AND
00000dde: JUMP
00000ddf: JUMPDEST
00000de0: SWAP2
00000de1: POP
00000de2: SWAP2
00000de3: POP
00000de4: DUP2
00000de5: PUSH2 0x0ded
00000de8: DUP6
00000de9: PUSH2 0x1102
00000dec: JUMP
00000ded: JUMPDEST
00000dee: SWAP1
00000def: PUSH2 0x0e25
00000df2: JUMPI
00000df3: PUSH1 0x40
00000df5: MLOAD
00000df6: PUSH32 0x08c379a000000000000000000000000000000000000000000000000000000000
00000e17: DUP2
00000e18: MSTORE
00000e19: PUSH1 0x04
00000e1b: ADD
00000e1c: PUSH2 0x05d7
00000e1f: SWAP2
00000e20: SWAP1
00000e21: PUSH2 0x1d72
00000e24: JUMP
00000e25: JUMPDEST
00000e26: POP
00000e27: SWAP4
00000e28: SWAP3
00000e29: POP
00000e2a: POP
00000e2b: POP
00000e2c: JUMP
00000e2d: JUMPDEST
00000e2e: PUSH1 0x00
00000e30: PUSH2 0x0e39
00000e33: DUP4
00000e34: DUP4
00000e35: PUSH2 0x1139
00000e38: JUMP
00000e39: JUMPDEST
00000e3a: SWAP1
00000e3b: POP
00000e3c: PUSH1 0x00
00000e3e: PUSH2 0x0e47
00000e41: DUP5
00000e42: DUP5
00000e43: PUSH2 0x1158
00000e46: JUMP
00000e47: JUMPDEST
00000e48: SWAP1
00000e49: POP
00000e4a: CALLDATASIZE
00000e4b: PUSH1 0x00
00000e4d: PUSH2 0x0e56
00000e50: DUP7
00000e51: DUP7
00000e52: PUSH2 0x1168
00000e55: JUMP
00000e56: JUMPDEST
00000e57: SWAP2
00000e58: POP
00000e59: SWAP2
00000e5a: POP
00000e5b: PUSH2 0x0e6c
00000e5e: PUSH2 0x0e64
00000e61: DUP6
00000e62: SWAP1
00000e63: JUMP
00000e64: JUMPDEST
00000e65: DUP5
00000e66: DUP5
00000e67: DUP5
00000e68: PUSH2 0x1178
00000e6b: JUMP
00000e6c: JUMPDEST
00000e6d: DUP4
00000e6e: DUP9
00000e6f: PUSH4 0xffffffff
00000e74: AND
00000e75: PUSH32 0xba20947a325f450d232530e5f5fce293e7963499d5309a07cee84a269f2f15a6
00000e96: DUP6
00000e97: PUSH1 0x40
00000e99: MLOAD
00000e9a: PUSH2 0x0ea5
00000e9d: SWAP2
00000e9e: DUP2
00000e9f: MSTORE
00000ea0: PUSH1 0x20
00000ea2: ADD
00000ea3: SWAP1
00000ea4: JUMP
00000ea5: JUMPDEST
00000ea6: PUSH1 0x40
00000ea8: MLOAD
00000ea9: DUP1
00000eaa: SWAP2
00000eab: SUB
00000eac: SWAP1
00000ead: LOG3
00000eae: POP
00000eaf: POP
00000eb0: POP
00000eb1: POP
00000eb2: POP
00000eb3: POP
00000eb4: POP
00000eb5: POP
00000eb6: JUMP
00000eb7: JUMPDEST
00000eb8: PUSH1 0x33
00000eba: DUP1
00000ebb: SLOAD
00000ebc: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
00000ed1: DUP4
00000ed2: DUP2
00000ed3: AND
00000ed4: PUSH32 0xffffffffffffffffffffffff0000000000000000000000000000000000000000
00000ef5: DUP4
00000ef6: AND
00000ef7: DUP2
00000ef8: OR
00000ef9: SWAP1
00000efa: SWAP4
00000efb: SSTORE
00000efc: PUSH1 0x40
00000efe: MLOAD
00000eff: SWAP2
00000f00: AND
00000f01: SWAP2
00000f02: SWAP1
00000f03: DUP3
00000f04: SWAP1
00000f05: PUSH32 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0
00000f26: SWAP1
00000f27: PUSH1 0x00
00000f29: SWAP1
00000f2a: LOG3
00000f2b: POP
00000f2c: POP
00000f2d: JUMP
00000f2e: JUMPDEST
00000f2f: PUSH2 0x0f42
00000f32: PUSH1 0x97
00000f34: PUSH4 0xffffffff
00000f39: DUP1
00000f3a: DUP5
00000f3b: AND
00000f3c: SWAP1
00000f3d: PUSH2 0x1182
00000f40: AND
00000f41: JUMP
00000f42: JUMPDEST
00000f43: PUSH2 0x0f4b
00000f46: DUP3
00000f47: PUSH2 0x1102
00000f4a: JUMP
00000f4b: JUMPDEST
00000f4c: SWAP1
00000f4d: PUSH2 0x0798
00000f50: JUMPI
00000f51: PUSH1 0x40
00000f53: MLOAD
00000f54: PUSH32 0x08c379a000000000000000000000000000000000000000000000000000000000
00000f75: DUP2
00000f76: MSTORE
00000f77: PUSH1 0x04
00000f79: ADD
00000f7a: PUSH2 0x05d7
00000f7d: SWAP2
00000f7e: SWAP1
00000f7f: PUSH2 0x1d72
00000f82: JUMP
00000f83: JUMPDEST
00000f84: PUSH1 0x00
00000f86: DUP1
00000f87: PUSH2 0x0f9b
00000f8a: PUSH1 0x40
00000f8c: DUP1
00000f8d: MLOAD
00000f8e: PUSH1 0x20
00000f90: DUP2
00000f91: ADD
00000f92: SWAP1
00000f93: SWAP2
00000f94: MSTORE
00000f95: PUSH1 0x00
00000f97: DUP2
00000f98: MSTORE
00000f99: SWAP1
00000f9a: JUMP
00000f9b: JUMPDEST
00000f9c: SWAP1
00000f9d: POP
00000f9e: PUSH2 0x0fb2
00000fa1: DUP7
00000fa2: DUP5
00000fa3: PUSH2 0x0fad
00000fa6: DUP9
00000fa7: DUP9
00000fa8: DUP7
00000fa9: PUSH2 0x118e
00000fac: JUMP
00000fad: JUMPDEST
00000fae: PUSH2 0x11bd
00000fb1: JUMP
00000fb2: JUMPDEST
00000fb3: SWAP2
00000fb4: POP
00000fb5: DUP5
00000fb6: DUP7
00000fb7: PUSH4 0xffffffff
00000fbc: AND
00000fbd: PUSH32 0xd229aacb94204188fe8042965fa6b269c62dc5818b21238779ab64bdd17efeec
00000fde: DUP7
00000fdf: PUSH1 0x40
00000fe1: MLOAD
00000fe2: PUSH2 0x0fed
00000fe5: SWAP2
00000fe6: DUP2
00000fe7: MSTORE
00000fe8: PUSH1 0x20
00000fea: ADD
00000feb: SWAP1
00000fec: JUMP
00000fed: JUMPDEST
00000fee: PUSH1 0x40
00000ff0: MLOAD
00000ff1: DUP1
00000ff2: SWAP2
00000ff3: SUB
00000ff4: SWAP1
00000ff5: LOG3
00000ff6: POP
00000ff7: SWAP5
00000ff8: SWAP4
00000ff9: POP
00000ffa: POP
00000ffb: POP
00000ffc: POP
00000ffd: JUMP
00000ffe: JUMPDEST
00000fff: PUSH2 0x0798
00001002: PUSH1 0x97
00001004: PUSH4 0xffffffff
00001009: DUP1
0000100a: DUP6
0000100b: AND
0000100c: SWAP1
0000100d: DUP5
0000100e: SWAP1
0000100f: PUSH2 0x11d7
00001012: AND
00001013: JUMP
00001014: JUMPDEST
00001015: PUSH1 0x00
00001017: DUP1
00001018: PUSH2 0x1020
0000101b: DUP5
0000101c: PUSH2 0x0dc7
0000101f: JUMP
00001020: JUMPDEST
00001021: SWAP1
00001022: POP
00001023: PUSH2 0x0647
00001026: DUP5
00001027: DUP3
00001028: DUP6
00001029: PUSH2 0x11e2
0000102c: JUMP
0000102d: JUMPDEST
0000102e: PUSH1 0x00
00001030: DUP2
00001031: DUP2
00001032: MSTORE
00001033: PUSH1 0x02
00001035: DUP4
00001036: ADD
00001037: PUSH1 0x20
00001039: MSTORE
0000103a: PUSH1 0x40
0000103c: DUP2
0000103d: KECCAK256
0000103e: SLOAD
0000103f: DUP2
00001040: SWAP1
00001041: DUP1
00001042: PUSH2 0x105c
00001045: JUMPI
00001046: PUSH2 0x104f
00001049: DUP6
0000104a: DUP6
0000104b: PUSH2 0x12c3
0000104e: JUMP
0000104f: JUMPDEST
00001050: SWAP3
00001051: POP
00001052: PUSH1 0x00
00001054: SWAP2
00001055: POP
00001056: PUSH2 0x0d05
00001059: SWAP1
0000105a: POP
0000105b: JUMP
0000105c: JUMPDEST
0000105d: PUSH1 0x01
0000105f: SWAP3
00001060: POP
00001061: SWAP1
00001062: POP
00001063: PUSH2 0x0d05
00001066: JUMP
00001067: JUMPDEST
00001068: PUSH1 0x60
0000106a: PUSH1 0x00
0000106c: PUSH2 0x1074
0000106f: DUP4
00001070: PUSH2 0x12cf
00001073: JUMP
00001074: JUMPDEST
00001075: SWAP1
00001076: POP
00001077: DUP1
00001078: PUSH8 0xffffffffffffffff
00001081: DUP2
00001082: GT
00001083: ISZERO
00001084: PUSH2 0x108f
00001087: JUMPI
00001088: PUSH2 0x108f
0000108b: PUSH2 0x1c9d
0000108e: JUMP
0000108f: JUMPDEST
00001090: PUSH1 0x40
00001092: MLOAD
00001093: SWAP1
00001094: DUP1
00001095: DUP3
00001096: MSTORE
00001097: DUP1
00001098: PUSH1 0x20
0000109a: MUL
0000109b: PUSH1 0x20
0000109d: ADD
0000109e: DUP3
0000109f: ADD
000010a0: PUSH1 0x40
000010a2: MSTORE
000010a3: DUP1
000010a4: ISZERO
000010a5: PUSH2 0x10b8
000010a8: JUMPI
000010a9: DUP2
000010aa: PUSH1 0x20
000010ac: ADD
000010ad: PUSH1 0x20
000010af: DUP3
000010b0: MUL
000010b1: DUP1
000010b2: CALLDATASIZE
000010b3: DUP4
000010b4: CALLDATACOPY
000010b5: ADD
000010b6: SWAP1
000010b7: POP
000010b8: JUMPDEST
000010b9: POP
000010ba: SWAP2
000010bb: POP
000010bc: PUSH1 0x00
000010be: JUMPDEST
000010bf: DUP2
000010c0: DUP2
000010c1: LT
000010c2: ISZERO
000010c3: PUSH2 0x0dc0
000010c6: JUMPI
000010c7: PUSH2 0x10d0
000010ca: DUP5
000010cb: DUP3
000010cc: PUSH2 0x12da
000010cf: JUMP
000010d0: JUMPDEST
000010d1: PUSH1 0x00
000010d3: SHR
000010d4: DUP4
000010d5: DUP3
000010d6: DUP2
000010d7: MLOAD
000010d8: DUP2
000010d9: LT
000010da: PUSH2 0x10e5
000010dd: JUMPI
000010de: PUSH2 0x10e5
000010e1: PUSH2 0x1c19
000010e4: JUMP
000010e5: JUMPDEST
000010e6: PUSH1 0x20
000010e8: SWAP1
000010e9: DUP2
000010ea: MUL
000010eb: SWAP2
000010ec: SWAP1
000010ed: SWAP2
000010ee: ADD
000010ef: ADD
000010f0: MSTORE
000010f1: DUP1
000010f2: PUSH2 0x10fa
000010f5: DUP2
000010f6: PUSH2 0x1ccc
000010f9: JUMP
000010fa: JUMPDEST
000010fb: SWAP2
000010fc: POP
000010fd: POP
000010fe: PUSH2 0x10be
00001101: JUMP
00001102: JUMPDEST
00001103: PUSH1 0x60
00001105: PUSH2 0x1113
00001108: DUP3
00001109: PUSH4 0xffffffff
0000110e: AND
0000110f: PUSH2 0x12e6
00001112: JUMP
00001113: JUMPDEST
00001114: PUSH1 0x40
00001116: MLOAD
00001117: PUSH1 0x20
00001119: ADD
0000111a: PUSH2 0x1123
0000111d: SWAP2
0000111e: SWAP1
0000111f: PUSH2 0x1d85
00001122: JUMP
00001123: JUMPDEST
00001124: PUSH1 0x40
00001126: MLOAD
00001127: PUSH1 0x20
00001129: DUP2
0000112a: DUP4
0000112b: SUB
0000112c: SUB
0000112d: DUP2
0000112e: MSTORE
0000112f: SWAP1
00001130: PUSH1 0x40
00001132: MSTORE
00001133: SWAP1
00001134: POP
00001135: SWAP2
00001136: SWAP1
00001137: POP
00001138: JUMP
00001139: JUMPDEST
0000113a: PUSH1 0x00
0000113c: PUSH2 0x1148
0000113f: PUSH1 0x20
00001141: DUP3
00001142: DUP5
00001143: DUP7
00001144: PUSH2 0x1dca
00001147: JUMP
00001148: JUMPDEST
00001149: PUSH2 0x1151
0000114c: SWAP2
0000114d: PUSH2 0x1df4
00001150: JUMP
00001151: JUMPDEST
00001152: SWAP4
00001153: SWAP3
00001154: POP
00001155: POP
00001156: POP
00001157: JUMP
00001158: JUMPDEST
00001159: PUSH1 0x00
0000115b: PUSH2 0x1148
0000115e: PUSH1 0x40
00001160: PUSH1 0x20
00001162: DUP5
00001163: DUP7
00001164: PUSH2 0x1dca
00001167: JUMP
00001168: JUMPDEST
00001169: CALLDATASIZE
0000116a: PUSH1 0x00
0000116c: PUSH2 0x0d00
0000116f: DUP4
00001170: PUSH1 0x40
00001172: DUP2
00001173: DUP8
00001174: PUSH2 0x1dca
00001177: JUMP
00001178: JUMPDEST
00001179: PUSH2 0x0979
0000117c: DUP5
0000117d: DUP5
0000117e: PUSH2 0x13a4
00001181: JUMP
00001182: JUMPDEST
00001183: PUSH1 0x00
00001185: PUSH2 0x1151
00001188: DUP4
00001189: DUP4
0000118a: PUSH2 0x14fe
0000118d: JUMP
0000118e: JUMPDEST
0000118f: PUSH1 0x60
00001191: DUP4
00001192: DUP4
00001193: DUP4
00001194: PUSH1 0x40
00001196: MLOAD
00001197: PUSH1 0x20
00001199: ADD
0000119a: PUSH2 0x11a5
0000119d: SWAP4
0000119e: SWAP3
0000119f: SWAP2
000011a0: SWAP1
000011a1: PUSH2 0x1e30
000011a4: JUMP
000011a5: JUMPDEST
000011a6: PUSH1 0x40
000011a8: MLOAD
000011a9: PUSH1 0x20
000011ab: DUP2
000011ac: DUP4
000011ad: SUB
000011ae: SUB
000011af: DUP2
000011b0: MSTORE
000011b1: SWAP1
000011b2: PUSH1 0x40
000011b4: MSTORE
000011b5: SWAP1
000011b6: POP
000011b7: SWAP4
000011b8: SWAP3
000011b9: POP
000011ba: POP
000011bb: POP
000011bc: JUMP
000011bd: JUMPDEST
000011be: PUSH1 0x00
000011c0: DUP1
000011c1: PUSH2 0x11c9
000011c4: DUP6
000011c5: PUSH2 0x0dc7
000011c8: JUMP
000011c9: JUMPDEST
000011ca: SWAP1
000011cb: POP
000011cc: PUSH2 0x0a05
000011cf: DUP6
000011d0: DUP3
000011d1: DUP7
000011d2: DUP7
000011d3: PUSH2 0x151b
000011d6: JUMP
000011d7: JUMPDEST
000011d8: PUSH2 0x0979
000011db: DUP4
000011dc: DUP4
000011dd: DUP4
000011de: PUSH2 0x15ff
000011e1: JUMP
000011e2: JUMPDEST
000011e3: PUSH1 0x00
000011e5: PUSH32 0x000000000000000000000000c005dc82818d67af737725bd4bf75435d065d239
00001206: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
0000121b: AND
0000121c: PUSH4 0x81d2ea95
00001221: DUP6
00001222: DUP6
00001223: DUP6
00001224: PUSH2 0x122c
00001227: DUP10
00001228: PUSH2 0x161c
0000122b: JUMP
0000122c: JUMPDEST
0000122d: PUSH1 0x65
0000122f: SLOAD
00001230: PUSH1 0x40
00001232: MLOAD
00001233: PUSH32 0xffffffff00000000000000000000000000000000000000000000000000000000
00001254: PUSH1 0xe0
00001256: DUP9
00001257: SWAP1
00001258: SHL
00001259: AND
0000125a: DUP2
0000125b: MSTORE
0000125c: PUSH2 0x1282
0000125f: SWAP6
00001260: SWAP5
00001261: SWAP4
00001262: SWAP3
00001263: SWAP2
00001264: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
00001279: AND
0000127a: SWAP1
0000127b: PUSH1 0x04
0000127d: ADD
0000127e: PUSH2 0x1e5d
00001281: JUMP
00001282: JUMPDEST
00001283: PUSH1 0x20
00001285: PUSH1 0x40
00001287: MLOAD
00001288: DUP1
00001289: DUP4
0000128a: SUB
0000128b: DUP2
0000128c: DUP7
0000128d: GAS
0000128e: STATICCALL
0000128f: ISZERO
00001290: DUP1
00001291: ISZERO
00001292: PUSH2 0x129f
00001295: JUMPI
00001296: RETURNDATASIZE
00001297: PUSH1 0x00
00001299: DUP1
0000129a: RETURNDATACOPY
0000129b: RETURNDATASIZE
0000129c: PUSH1 0x00
0000129e: REVERT
0000129f: JUMPDEST
000012a0: POP
000012a1: POP
000012a2: POP
000012a3: POP
000012a4: PUSH1 0x40
000012a6: MLOAD
000012a7: RETURNDATASIZE
000012a8: PUSH1 0x1f
000012aa: NOT
000012ab: PUSH1 0x1f
000012ad: DUP3
000012ae: ADD
000012af: AND
000012b0: DUP3
000012b1: ADD
000012b2: DUP1
000012b3: PUSH1 0x40
000012b5: MSTORE
000012b6: POP
000012b7: DUP2
000012b8: ADD
000012b9: SWAP1
000012ba: PUSH2 0x0647
000012bd: SWAP2
000012be: SWAP1
000012bf: PUSH2 0x1ebd
000012c2: JUMP
000012c3: JUMPDEST
000012c4: PUSH1 0x00
000012c6: PUSH2 0x1151
000012c9: DUP4
000012ca: DUP4
000012cb: PUSH2 0x163e
000012ce: JUMP
000012cf: JUMPDEST
000012d0: PUSH1 0x00
000012d2: PUSH2 0x0bb8
000012d5: DUP3
000012d6: PUSH2 0x1656
000012d9: JUMP
000012da: JUMPDEST
000012db: PUSH1 0x00
000012dd: PUSH2 0x1151
000012e0: DUP4
000012e1: DUP4
000012e2: PUSH2 0x1660
000012e5: JUMP
000012e6: JUMPDEST
000012e7: PUSH1 0x60
000012e9: PUSH1 0x00
000012eb: PUSH2 0x12f3
000012ee: DUP4
000012ef: PUSH2 0x168a
000012f2: JUMP
000012f3: JUMPDEST
000012f4: PUSH1 0x01
000012f6: ADD
000012f7: SWAP1
000012f8: POP
000012f9: PUSH1 0x00
000012fb: DUP2
000012fc: PUSH8 0xffffffffffffffff
00001305: DUP2
00001306: GT
00001307: ISZERO
00001308: PUSH2 0x1313
0000130b: JUMPI
0000130c: PUSH2 0x1313
0000130f: PUSH2 0x1c9d
00001312: JUMP
00001313: JUMPDEST
00001314: PUSH1 0x40
00001316: MLOAD
00001317: SWAP1
00001318: DUP1
00001319: DUP3
0000131a: MSTORE
0000131b: DUP1
0000131c: PUSH1 0x1f
0000131e: ADD
0000131f: PUSH1 0x1f
00001321: NOT
00001322: AND
00001323: PUSH1 0x20
00001325: ADD
00001326: DUP3
00001327: ADD
00001328: PUSH1 0x40
0000132a: MSTORE
0000132b: DUP1
0000132c: ISZERO
0000132d: PUSH2 0x133d
00001330: JUMPI
00001331: PUSH1 0x20
00001333: DUP3
00001334: ADD
00001335: DUP2
00001336: DUP1
00001337: CALLDATASIZE
00001338: DUP4
00001339: CALLDATACOPY
0000133a: ADD
0000133b: SWAP1
0000133c: POP
0000133d: JUMPDEST
0000133e: POP
0000133f: SWAP1
00001340: POP
00001341: DUP2
00001342: DUP2
00001343: ADD
00001344: PUSH1 0x20
00001346: ADD
00001347: JUMPDEST
00001348: PUSH32 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
00001369: ADD
0000136a: PUSH32 0x3031323334353637383961626364656600000000000000000000000000000000
0000138b: PUSH1 0x0a
0000138d: DUP7
0000138e: MOD
0000138f: BYTE
00001390: DUP2
00001391: MSTORE8
00001392: PUSH1 0x0a
00001394: DUP6
00001395: DIV
00001396: SWAP5
00001397: POP
00001398: DUP5
00001399: PUSH2 0x1347
0000139c: JUMPI
0000139d: POP
0000139e: SWAP4
0000139f: SWAP3
000013a0: POP
000013a1: POP
000013a2: POP
000013a3: JUMP
000013a4: JUMPDEST
000013a5: DUP1
000013a6: SELFBALANCE
000013a7: LT
000013a8: ISZERO
000013a9: PUSH2 0x140e
000013ac: JUMPI
000013ad: PUSH1 0x40
000013af: MLOAD
000013b0: PUSH32 0x08c379a000000000000000000000000000000000000000000000000000000000
000013d1: DUP2
000013d2: MSTORE
000013d3: PUSH1 0x20
000013d5: PUSH1 0x04
000013d7: DUP3
000013d8: ADD
000013d9: MSTORE
000013da: PUSH1 0x1d
000013dc: PUSH1 0x24
000013de: DUP3
000013df: ADD
000013e0: MSTORE
000013e1: PUSH32 0x416464726573733a20696e73756666696369656e742062616c616e6365000000
00001402: PUSH1 0x44
00001404: DUP3
00001405: ADD
00001406: MSTORE
00001407: PUSH1 0x64
00001409: ADD
0000140a: PUSH2 0x05d7
0000140d: JUMP
0000140e: JUMPDEST
0000140f: PUSH1 0x00
00001411: DUP3
00001412: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
00001427: AND
00001428: DUP3
00001429: PUSH1 0x40
0000142b: MLOAD
0000142c: PUSH1 0x00
0000142e: PUSH1 0x40
00001430: MLOAD
00001431: DUP1
00001432: DUP4
00001433: SUB
00001434: DUP2
00001435: DUP6
00001436: DUP8
00001437: GAS
00001438: CALL
00001439: SWAP3
0000143a: POP
0000143b: POP
0000143c: POP
0000143d: RETURNDATASIZE
0000143e: DUP1
0000143f: PUSH1 0x00
00001441: DUP2
00001442: EQ
00001443: PUSH2 0x1468
00001446: JUMPI
00001447: PUSH1 0x40
00001449: MLOAD
0000144a: SWAP2
0000144b: POP
0000144c: PUSH1 0x1f
0000144e: NOT
0000144f: PUSH1 0x3f
00001451: RETURNDATASIZE
00001452: ADD
00001453: AND
00001454: DUP3
00001455: ADD
00001456: PUSH1 0x40
00001458: MSTORE
00001459: RETURNDATASIZE
0000145a: DUP3
0000145b: MSTORE
0000145c: RETURNDATASIZE
0000145d: PUSH1 0x00
0000145f: PUSH1 0x20
00001461: DUP5
00001462: ADD
00001463: RETURNDATACOPY
00001464: PUSH2 0x146d
00001467: JUMP
00001468: JUMPDEST
00001469: PUSH1 0x60
0000146b: SWAP2
0000146c: POP
0000146d: JUMPDEST
0000146e: POP
0000146f: POP
00001470: SWAP1
00001471: POP
00001472: DUP1
00001473: PUSH2 0x0a93
00001476: JUMPI
00001477: PUSH1 0x40
00001479: MLOAD
0000147a: PUSH32 0x08c379a000000000000000000000000000000000000000000000000000000000
0000149b: DUP2
0000149c: MSTORE
0000149d: PUSH1 0x20
0000149f: PUSH1 0x04
000014a1: DUP3
000014a2: ADD
000014a3: MSTORE
000014a4: PUSH1 0x3a
000014a6: PUSH1 0x24
000014a8: DUP3
000014a9: ADD
000014aa: MSTORE
000014ab: PUSH32 0x416464726573733a20756e61626c6520746f2073656e642076616c75652c2072
000014cc: PUSH1 0x44
000014ce: DUP3
000014cf: ADD
000014d0: MSTORE
000014d1: PUSH32 0x6563697069656e74206d61792068617665207265766572746564000000000000
000014f2: PUSH1 0x64
000014f4: DUP3
000014f5: ADD
000014f6: MSTORE
000014f7: PUSH1 0x84
000014f9: ADD
000014fa: PUSH2 0x05d7
000014fd: JUMP
000014fe: JUMPDEST
000014ff: PUSH1 0x00
00001501: DUP2
00001502: DUP2
00001503: MSTORE
00001504: PUSH1 0x02
00001506: DUP4
00001507: ADD
00001508: PUSH1 0x20
0000150a: MSTORE
0000150b: PUSH1 0x40
0000150d: DUP2
0000150e: KECCAK256
0000150f: DUP2
00001510: SWAP1
00001511: SSTORE
00001512: PUSH2 0x1151
00001515: DUP4
00001516: DUP4
00001517: PUSH2 0x176c
0000151a: JUMP
0000151b: JUMPDEST
0000151c: PUSH1 0x00
0000151e: PUSH32 0x000000000000000000000000c005dc82818d67af737725bd4bf75435d065d239
0000153f: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
00001554: AND
00001555: PUSH4 0x10b83dc0
0000155a: DUP5
0000155b: DUP8
0000155c: DUP8
0000155d: DUP7
0000155e: PUSH2 0x1566
00001561: DUP12
00001562: PUSH2 0x161c
00001565: JUMP
00001566: JUMPDEST
00001567: PUSH1 0x65
00001569: SLOAD
0000156a: PUSH1 0x40
0000156c: MLOAD
0000156d: PUSH32 0xffffffff00000000000000000000000000000000000000000000000000000000
0000158e: PUSH1 0xe0
00001590: DUP10
00001591: SWAP1
00001592: SHL
00001593: AND
00001594: DUP2
00001595: MSTORE
00001596: PUSH2 0x15bc
00001599: SWAP6
0000159a: SWAP5
0000159b: SWAP4
0000159c: SWAP3
0000159d: SWAP2
0000159e: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
000015b3: AND
000015b4: SWAP1
000015b5: PUSH1 0x04
000015b7: ADD
000015b8: PUSH2 0x1e5d
000015bb: JUMP
000015bc: JUMPDEST
000015bd: PUSH1 0x20
000015bf: PUSH1 0x40
000015c1: MLOAD
000015c2: DUP1
000015c3: DUP4
000015c4: SUB
000015c5: DUP2
000015c6: DUP6
000015c7: DUP9
000015c8: GAS
000015c9: CALL
000015ca: ISZERO
000015cb: DUP1
000015cc: ISZERO
000015cd: PUSH2 0x15da
000015d0: JUMPI
000015d1: RETURNDATASIZE
000015d2: PUSH1 0x00
000015d4: DUP1
000015d5: RETURNDATACOPY
000015d6: RETURNDATASIZE
000015d7: PUSH1 0x00
000015d9: REVERT
000015da: JUMPDEST
000015db: POP
000015dc: POP
000015dd: POP
000015de: POP
000015df: POP
000015e0: PUSH1 0x40
000015e2: MLOAD
000015e3: RETURNDATASIZE
000015e4: PUSH1 0x1f
000015e6: NOT
000015e7: PUSH1 0x1f
000015e9: DUP3
000015ea: ADD
000015eb: AND
000015ec: DUP3
000015ed: ADD
000015ee: DUP1
000015ef: PUSH1 0x40
000015f1: MSTORE
000015f2: POP
000015f3: DUP2
000015f4: ADD
000015f5: SWAP1
000015f6: PUSH2 0x0a05
000015f9: SWAP2
000015fa: SWAP1
000015fb: PUSH2 0x1ebd
000015fe: JUMP
000015ff: JUMPDEST
00001600: PUSH1 0x00
00001602: DUP3
00001603: DUP2
00001604: MSTORE
00001605: PUSH1 0x02
00001607: DUP5
00001608: ADD
00001609: PUSH1 0x20
0000160b: MSTORE
0000160c: PUSH1 0x40
0000160e: DUP2
0000160f: KECCAK256
00001610: DUP3
00001611: SWAP1
00001612: SSTORE
00001613: PUSH2 0x0647
00001616: DUP5
00001617: DUP5
00001618: PUSH2 0x1778
0000161b: JUMP
0000161c: JUMPDEST
0000161d: PUSH4 0xffffffff
00001622: DUP2
00001623: AND
00001624: PUSH1 0x00
00001626: SWAP1
00001627: DUP2
00001628: MSTORE
00001629: PUSH1 0xca
0000162b: PUSH1 0x20
0000162d: MSTORE
0000162e: PUSH1 0x40
00001630: SWAP1
00001631: KECCAK256
00001632: SLOAD
00001633: PUSH1 0x60
00001635: SWAP1
00001636: PUSH2 0x0bb8
00001639: SWAP1
0000163a: PUSH2 0x1784
0000163d: JUMP
0000163e: JUMPDEST
0000163f: PUSH1 0x00
00001641: DUP2
00001642: DUP2
00001643: MSTORE
00001644: PUSH1 0x01
00001646: DUP4
00001647: ADD
00001648: PUSH1 0x20
0000164a: MSTORE
0000164b: PUSH1 0x40
0000164d: DUP2
0000164e: KECCAK256
0000164f: SLOAD
00001650: ISZERO
00001651: ISZERO
00001652: PUSH2 0x1151
00001655: JUMP
00001656: JUMPDEST
00001657: PUSH1 0x00
00001659: PUSH2 0x0bb8
0000165c: DUP3
0000165d: SLOAD
0000165e: SWAP1
0000165f: JUMP
00001660: JUMPDEST
00001661: PUSH1 0x00
00001663: DUP3
00001664: PUSH1 0x00
00001666: ADD
00001667: DUP3
00001668: DUP2
00001669: SLOAD
0000166a: DUP2
0000166b: LT
0000166c: PUSH2 0x1677
0000166f: JUMPI
00001670: PUSH2 0x1677
00001673: PUSH2 0x1c19
00001676: JUMP
00001677: JUMPDEST
00001678: SWAP1
00001679: PUSH1 0x00
0000167b: MSTORE
0000167c: PUSH1 0x20
0000167e: PUSH1 0x00
00001680: KECCAK256
00001681: ADD
00001682: SLOAD
00001683: SWAP1
00001684: POP
00001685: SWAP3
00001686: SWAP2
00001687: POP
00001688: POP
00001689: JUMP
0000168a: JUMPDEST
0000168b: PUSH1 0x00
0000168d: DUP1
0000168e: PUSH27 0x184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000
000016aa: DUP4
000016ab: LT
000016ac: PUSH2 0x16d3
000016af: JUMPI
000016b0: PUSH27 0x184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000
000016cc: DUP4
000016cd: DIV
000016ce: SWAP3
000016cf: POP
000016d0: PUSH1 0x40
000016d2: ADD
000016d3: JUMPDEST
000016d4: PUSH14 0x04ee2d6d415b85acef8100000000
000016e3: DUP4
000016e4: LT
000016e5: PUSH2 0x16ff
000016e8: JUMPI
000016e9: PUSH14 0x04ee2d6d415b85acef8100000000
000016f8: DUP4
000016f9: DIV
000016fa: SWAP3
000016fb: POP
000016fc: PUSH1 0x20
000016fe: ADD
000016ff: JUMPDEST
00001700: PUSH7 0x2386f26fc10000
00001708: DUP4
00001709: LT
0000170a: PUSH2 0x171d
0000170d: JUMPI
0000170e: PUSH7 0x2386f26fc10000
00001716: DUP4
00001717: DIV
00001718: SWAP3
00001719: POP
0000171a: PUSH1 0x10
0000171c: ADD
0000171d: JUMPDEST
0000171e: PUSH4 0x05f5e100
00001723: DUP4
00001724: LT
00001725: PUSH2 0x1735
00001728: JUMPI
00001729: PUSH4 0x05f5e100
0000172e: DUP4
0000172f: DIV
00001730: SWAP3
00001731: POP
00001732: PUSH1 0x08
00001734: ADD
00001735: JUMPDEST
00001736: PUSH2 0x2710
00001739: DUP4
0000173a: LT
0000173b: PUSH2 0x1749
0000173e: JUMPI
0000173f: PUSH2 0x2710
00001742: DUP4
00001743: DIV
00001744: SWAP3
00001745: POP
00001746: PUSH1 0x04
00001748: ADD
00001749: JUMPDEST
0000174a: PUSH1 0x64
0000174c: DUP4
0000174d: LT
0000174e: PUSH2 0x175b
00001751: JUMPI
00001752: PUSH1 0x64
00001754: DUP4
00001755: DIV
00001756: SWAP3
00001757: POP
00001758: PUSH1 0x02
0000175a: ADD
0000175b: JUMPDEST
0000175c: PUSH1 0x0a
0000175e: DUP4
0000175f: LT
00001760: PUSH2 0x0bb8
00001763: JUMPI
00001764: PUSH1 0x01
00001766: ADD
00001767: SWAP3
00001768: SWAP2
00001769: POP
0000176a: POP
0000176b: JUMP
0000176c: JUMPDEST
0000176d: PUSH1 0x00
0000176f: PUSH2 0x1151
00001772: DUP4
00001773: DUP4
00001774: PUSH2 0x17a2
00001777: JUMP
00001778: JUMPDEST
00001779: PUSH1 0x00
0000177b: PUSH2 0x1151
0000177e: DUP4
0000177f: DUP4
00001780: PUSH2 0x1895
00001783: JUMP
00001784: JUMPDEST
00001785: PUSH1 0x60
00001787: PUSH2 0x0bb8
0000178a: PUSH1 0x00
0000178c: DUP4
0000178d: CALLER
0000178e: PUSH1 0x40
00001790: MLOAD
00001791: DUP1
00001792: PUSH1 0x20
00001794: ADD
00001795: PUSH1 0x40
00001797: MSTORE
00001798: DUP1
00001799: PUSH1 0x00
0000179b: DUP2
0000179c: MSTORE
0000179d: POP
0000179e: PUSH2 0x18e4
000017a1: JUMP
000017a2: JUMPDEST
000017a3: PUSH1 0x00
000017a5: DUP2
000017a6: DUP2
000017a7: MSTORE
000017a8: PUSH1 0x01
000017aa: DUP4
000017ab: ADD
000017ac: PUSH1 0x20
000017ae: MSTORE
000017af: PUSH1 0x40
000017b1: DUP2
000017b2: KECCAK256
000017b3: SLOAD
000017b4: DUP1
000017b5: ISZERO
000017b6: PUSH2 0x188b
000017b9: JUMPI
000017ba: PUSH1 0x00
000017bc: PUSH2 0x17c6
000017bf: PUSH1 0x01
000017c1: DUP4
000017c2: PUSH2 0x1c8a
000017c5: JUMP
000017c6: JUMPDEST
000017c7: DUP6
000017c8: SLOAD
000017c9: SWAP1
000017ca: SWAP2
000017cb: POP
000017cc: PUSH1 0x00
000017ce: SWAP1
000017cf: PUSH2 0x17da
000017d2: SWAP1
000017d3: PUSH1 0x01
000017d5: SWAP1
000017d6: PUSH2 0x1c8a
000017d9: JUMP
000017da: JUMPDEST
000017db: SWAP1
000017dc: POP
000017dd: DUP2
000017de: DUP2
000017df: EQ
000017e0: PUSH2 0x183f
000017e3: JUMPI
000017e4: PUSH1 0x00
000017e6: DUP7
000017e7: PUSH1 0x00
000017e9: ADD
000017ea: DUP3
000017eb: DUP2
000017ec: SLOAD
000017ed: DUP2
000017ee: LT
000017ef: PUSH2 0x17fa
000017f2: JUMPI
000017f3: PUSH2 0x17fa
000017f6: PUSH2 0x1c19
000017f9: JUMP
000017fa: JUMPDEST
000017fb: SWAP1
000017fc: PUSH1 0x00
000017fe: MSTORE
000017ff: PUSH1 0x20
00001801: PUSH1 0x00
00001803: KECCAK256
00001804: ADD
00001805: SLOAD
00001806: SWAP1
00001807: POP
00001808: DUP1
00001809: DUP8
0000180a: PUSH1 0x00
0000180c: ADD
0000180d: DUP5
0000180e: DUP2
0000180f: SLOAD
00001810: DUP2
00001811: LT
00001812: PUSH2 0x181d
00001815: JUMPI
00001816: PUSH2 0x181d
00001819: PUSH2 0x1c19
0000181c: JUMP
0000181d: JUMPDEST
0000181e: PUSH1 0x00
00001820: SWAP2
00001821: DUP3
00001822: MSTORE
00001823: PUSH1 0x20
00001825: DUP1
00001826: DUP4
00001827: KECCAK256
00001828: SWAP1
00001829: SWAP2
0000182a: ADD
0000182b: SWAP3
0000182c: SWAP1
0000182d: SWAP3
0000182e: SSTORE
0000182f: SWAP2
00001830: DUP3
00001831: MSTORE
00001832: PUSH1 0x01
00001834: DUP9
00001835: ADD
00001836: SWAP1
00001837: MSTORE
00001838: PUSH1 0x40
0000183a: SWAP1
0000183b: KECCAK256
0000183c: DUP4
0000183d: SWAP1
0000183e: SSTORE
0000183f: JUMPDEST
00001840: DUP6
00001841: SLOAD
00001842: DUP7
00001843: SWAP1
00001844: DUP1
00001845: PUSH2 0x1850
00001848: JUMPI
00001849: PUSH2 0x1850
0000184c: PUSH2 0x1ed6
0000184f: JUMP
00001850: JUMPDEST
00001851: PUSH1 0x01
00001853: SWAP1
00001854: SUB
00001855: DUP2
00001856: DUP2
00001857: SWAP1
00001858: PUSH1 0x00
0000185a: MSTORE
0000185b: PUSH1 0x20
0000185d: PUSH1 0x00
0000185f: KECCAK256
00001860: ADD
00001861: PUSH1 0x00
00001863: SWAP1
00001864: SSTORE
00001865: SWAP1
00001866: SSTORE
00001867: DUP6
00001868: PUSH1 0x01
0000186a: ADD
0000186b: PUSH1 0x00
0000186d: DUP7
0000186e: DUP2
0000186f: MSTORE
00001870: PUSH1 0x20
00001872: ADD
00001873: SWAP1
00001874: DUP2
00001875: MSTORE
00001876: PUSH1 0x20
00001878: ADD
00001879: PUSH1 0x00
0000187b: KECCAK256
0000187c: PUSH1 0x00
0000187e: SWAP1
0000187f: SSTORE
00001880: PUSH1 0x01
00001882: SWAP4
00001883: POP
00001884: POP
00001885: POP
00001886: POP
00001887: PUSH2 0x0bb8
0000188a: JUMP
0000188b: JUMPDEST
0000188c: PUSH1 0x00
0000188e: SWAP2
0000188f: POP
00001890: POP
00001891: PUSH2 0x0bb8
00001894: JUMP
00001895: JUMPDEST
00001896: PUSH1 0x00
00001898: DUP2
00001899: DUP2
0000189a: MSTORE
0000189b: PUSH1 0x01
0000189d: DUP4
0000189e: ADD
0000189f: PUSH1 0x20
000018a1: MSTORE
000018a2: PUSH1 0x40
000018a4: DUP2
000018a5: KECCAK256
000018a6: SLOAD
000018a7: PUSH2 0x18dc
000018aa: JUMPI
000018ab: POP
000018ac: DUP2
000018ad: SLOAD
000018ae: PUSH1 0x01
000018b0: DUP2
000018b1: DUP2
000018b2: ADD
000018b3: DUP5
000018b4: SSTORE
000018b5: PUSH1 0x00
000018b7: DUP5
000018b8: DUP2
000018b9: MSTORE
000018ba: PUSH1 0x20
000018bc: DUP1
000018bd: DUP3
000018be: KECCAK256
000018bf: SWAP1
000018c0: SWAP4
000018c1: ADD
000018c2: DUP5
000018c3: SWAP1
000018c4: SSTORE
000018c5: DUP5
000018c6: SLOAD
000018c7: DUP5
000018c8: DUP3
000018c9: MSTORE
000018ca: DUP3
000018cb: DUP7
000018cc: ADD
000018cd: SWAP1
000018ce: SWAP4
000018cf: MSTORE
000018d0: PUSH1 0x40
000018d2: SWAP1
000018d3: KECCAK256
000018d4: SWAP2
000018d5: SWAP1
000018d6: SWAP2
000018d7: SSTORE
000018d8: PUSH2 0x0bb8
000018db: JUMP
000018dc: JUMPDEST
000018dd: POP
000018de: PUSH1 0x00
000018e0: PUSH2 0x0bb8
000018e3: JUMP
000018e4: JUMPDEST
000018e5: PUSH1 0x60
000018e7: PUSH1 0x01
000018e9: DUP6
000018ea: DUP6
000018eb: DUP6
000018ec: DUP6
000018ed: PUSH1 0x40
000018ef: MLOAD
000018f0: PUSH1 0x20
000018f2: ADD
000018f3: PUSH2 0x1900
000018f6: SWAP6
000018f7: SWAP5
000018f8: SWAP4
000018f9: SWAP3
000018fa: SWAP2
000018fb: SWAP1
000018fc: PUSH2 0x1f05
000018ff: JUMP
00001900: JUMPDEST
00001901: PUSH1 0x40
00001903: MLOAD
00001904: PUSH1 0x20
00001906: DUP2
00001907: DUP4
00001908: SUB
00001909: SUB
0000190a: DUP2
0000190b: MSTORE
0000190c: SWAP1
0000190d: PUSH1 0x40
0000190f: MSTORE
00001910: SWAP1
00001911: POP
00001912: SWAP5
00001913: SWAP4
00001914: POP
00001915: POP
00001916: POP
00001917: POP
00001918: JUMP
00001919: JUMPDEST
0000191a: PUSH1 0x00
0000191c: PUSH1 0x20
0000191e: DUP3
0000191f: DUP5
00001920: SUB
00001921: SLT
00001922: ISZERO
00001923: PUSH2 0x192b
00001926: JUMPI
00001927: PUSH1 0x00
00001929: DUP1
0000192a: REVERT
0000192b: JUMPDEST
0000192c: DUP2
0000192d: CALLDATALOAD
0000192e: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
00001943: DUP2
00001944: AND
00001945: DUP2
00001946: EQ
00001947: PUSH2 0x1151
0000194a: JUMPI
0000194b: PUSH1 0x00
0000194d: DUP1
0000194e: REVERT
0000194f: JUMPDEST
00001950: DUP1
00001951: CALLDATALOAD
00001952: PUSH4 0xffffffff
00001957: DUP2
00001958: AND
00001959: DUP2
0000195a: EQ
0000195b: PUSH2 0x1963
0000195e: JUMPI
0000195f: PUSH1 0x00
00001961: DUP1
00001962: REVERT
00001963: JUMPDEST
00001964: SWAP2
00001965: SWAP1
00001966: POP
00001967: JUMP
00001968: JUMPDEST
00001969: PUSH1 0x00
0000196b: PUSH1 0x20
0000196d: DUP3
0000196e: DUP5
0000196f: SUB
00001970: SLT
00001971: ISZERO
00001972: PUSH2 0x197a
00001975: JUMPI
00001976: PUSH1 0x00
00001978: DUP1
00001979: REVERT
0000197a: JUMPDEST
0000197b: PUSH2 0x1151
0000197e: DUP3
0000197f: PUSH2 0x194f
00001982: JUMP
00001983: JUMPDEST
00001984: PUSH1 0x20
00001986: DUP1
00001987: DUP3
00001988: MSTORE
00001989: DUP3
0000198a: MLOAD
0000198b: DUP3
0000198c: DUP3
0000198d: ADD
0000198e: DUP2
0000198f: SWAP1
00001990: MSTORE
00001991: PUSH1 0x00
00001993: SWAP2
00001994: SWAP1
00001995: DUP5
00001996: DUP3
00001997: ADD
00001998: SWAP1
00001999: PUSH1 0x40
0000199b: DUP6
0000199c: ADD
0000199d: SWAP1
0000199e: DUP5
0000199f: JUMPDEST
000019a0: DUP2
000019a1: DUP2
000019a2: LT
000019a3: ISZERO
000019a4: PUSH2 0x19c1
000019a7: JUMPI
000019a8: DUP4
000019a9: MLOAD
000019aa: PUSH4 0xffffffff
000019af: AND
000019b0: DUP4
000019b1: MSTORE
000019b2: SWAP3
000019b3: DUP5
000019b4: ADD
000019b5: SWAP3
000019b6: SWAP2
000019b7: DUP5
000019b8: ADD
000019b9: SWAP2
000019ba: PUSH1 0x01
000019bc: ADD
000019bd: PUSH2 0x199f
000019c0: JUMP
000019c1: JUMPDEST
000019c2: POP
000019c3: SWAP1
000019c4: SWAP7
000019c5: SWAP6
000019c6: POP
000019c7: POP
000019c8: POP
000019c9: POP
000019ca: POP
000019cb: POP
000019cc: JUMP
000019cd: JUMPDEST
000019ce: PUSH1 0x00
000019d0: DUP1
000019d1: PUSH1 0x40
000019d3: DUP4
000019d4: DUP6
000019d5: SUB
000019d6: SLT
000019d7: ISZERO
000019d8: PUSH2 0x19e0
000019db: JUMPI
000019dc: PUSH1 0x00
000019de: DUP1
000019df: REVERT
000019e0: JUMPDEST
000019e1: PUSH2 0x19e9
000019e4: DUP4
000019e5: PUSH2 0x194f
000019e8: JUMP
000019e9: JUMPDEST
000019ea: SWAP5
000019eb: PUSH1 0x20
000019ed: SWAP4
000019ee: SWAP1
000019ef: SWAP4
000019f0: ADD
000019f1: CALLDATALOAD
000019f2: SWAP4
000019f3: POP
000019f4: POP
000019f5: POP
000019f6: JUMP
000019f7: JUMPDEST
000019f8: PUSH1 0x00
000019fa: DUP1
000019fb: PUSH1 0x00
000019fd: DUP1
000019fe: PUSH1 0x60
00001a00: DUP6
00001a01: DUP8
00001a02: SUB
00001a03: SLT
00001a04: ISZERO
00001a05: PUSH2 0x1a0d
00001a08: JUMPI
00001a09: PUSH1 0x00
00001a0b: DUP1
00001a0c: REVERT
00001a0d: JUMPDEST
00001a0e: PUSH2 0x1a16
00001a11: DUP6
00001a12: PUSH2 0x194f
00001a15: JUMP
00001a16: JUMPDEST
00001a17: SWAP4
00001a18: POP
00001a19: PUSH1 0x20
00001a1b: DUP6
00001a1c: ADD
00001a1d: CALLDATALOAD
00001a1e: SWAP3
00001a1f: POP
00001a20: PUSH1 0x40
00001a22: DUP6
00001a23: ADD
00001a24: CALLDATALOAD
00001a25: PUSH8 0xffffffffffffffff
00001a2e: DUP1
00001a2f: DUP3
00001a30: GT
00001a31: ISZERO
00001a32: PUSH2 0x1a3a
00001a35: JUMPI
00001a36: PUSH1 0x00
00001a38: DUP1
00001a39: REVERT
00001a3a: JUMPDEST
00001a3b: DUP2
00001a3c: DUP8
00001a3d: ADD
00001a3e: SWAP2
00001a3f: POP
00001a40: DUP8
00001a41: PUSH1 0x1f
00001a43: DUP4
00001a44: ADD
00001a45: SLT
00001a46: PUSH2 0x1a4e
00001a49: JUMPI
00001a4a: PUSH1 0x00
00001a4c: DUP1
00001a4d: REVERT
00001a4e: JUMPDEST
00001a4f: DUP2
00001a50: CALLDATALOAD
00001a51: DUP2
00001a52: DUP2
00001a53: GT
00001a54: ISZERO
00001a55: PUSH2 0x1a5d
00001a58: JUMPI
00001a59: PUSH1 0x00
00001a5b: DUP1
00001a5c: REVERT
00001a5d: JUMPDEST
00001a5e: DUP9
00001a5f: PUSH1 0x20
00001a61: DUP3
00001a62: DUP6
00001a63: ADD
00001a64: ADD
00001a65: GT
00001a66: ISZERO
00001a67: PUSH2 0x1a6f
00001a6a: JUMPI
00001a6b: PUSH1 0x00
00001a6d: DUP1
00001a6e: REVERT
00001a6f: JUMPDEST
00001a70: SWAP6
00001a71: SWAP9
00001a72: SWAP5
00001a73: SWAP8
00001a74: POP
00001a75: POP
00001a76: PUSH1 0x20
00001a78: ADD
00001a79: SWAP5
00001a7a: POP
00001a7b: POP
00001a7c: POP
00001a7d: JUMP
00001a7e: JUMPDEST
00001a7f: PUSH1 0x00
00001a81: DUP1
00001a82: DUP4
00001a83: PUSH1 0x1f
00001a85: DUP5
00001a86: ADD
00001a87: SLT
00001a88: PUSH2 0x1a90
00001a8b: JUMPI
00001a8c: PUSH1 0x00
00001a8e: DUP1
00001a8f: REVERT
00001a90: JUMPDEST
00001a91: POP
00001a92: DUP2
00001a93: CALLDATALOAD
00001a94: PUSH8 0xffffffffffffffff
00001a9d: DUP2
00001a9e: GT
00001a9f: ISZERO
00001aa0: PUSH2 0x1aa8
00001aa3: JUMPI
00001aa4: PUSH1 0x00
00001aa6: DUP1
00001aa7: REVERT
00001aa8: JUMPDEST
00001aa9: PUSH1 0x20
00001aab: DUP4
00001aac: ADD
00001aad: SWAP2
00001aae: POP
00001aaf: DUP4
00001ab0: PUSH1 0x20
00001ab2: DUP3
00001ab3: PUSH1 0x05
00001ab5: SHL
00001ab6: DUP6
00001ab7: ADD
00001ab8: ADD
00001ab9: GT
00001aba: ISZERO
00001abb: PUSH2 0x0d05
00001abe: JUMPI
00001abf: PUSH1 0x00
00001ac1: DUP1
00001ac2: REVERT
00001ac3: JUMPDEST
00001ac4: PUSH1 0x00
00001ac6: DUP1
00001ac7: PUSH1 0x20
00001ac9: DUP4
00001aca: DUP6
00001acb: SUB
00001acc: SLT
00001acd: ISZERO
00001ace: PUSH2 0x1ad6
00001ad1: JUMPI
00001ad2: PUSH1 0x00
00001ad4: DUP1
00001ad5: REVERT
00001ad6: JUMPDEST
00001ad7: DUP3
00001ad8: CALLDATALOAD
00001ad9: PUSH8 0xffffffffffffffff
00001ae2: DUP2
00001ae3: GT
00001ae4: ISZERO
00001ae5: PUSH2 0x1aed
00001ae8: JUMPI
00001ae9: PUSH1 0x00
00001aeb: DUP1
00001aec: REVERT
00001aed: JUMPDEST
00001aee: PUSH2 0x1af9
00001af1: DUP6
00001af2: DUP3
00001af3: DUP7
00001af4: ADD
00001af5: PUSH2 0x1a7e
00001af8: JUMP
00001af9: JUMPDEST
00001afa: SWAP1
00001afb: SWAP7
00001afc: SWAP1
00001afd: SWAP6
00001afe: POP
00001aff: SWAP4
00001b00: POP
00001b01: POP
00001b02: POP
00001b03: POP
00001b04: JUMP
00001b05: JUMPDEST
00001b06: PUSH1 0x00
00001b08: DUP1
00001b09: PUSH1 0x00
00001b0b: PUSH1 0x60
00001b0d: DUP5
00001b0e: DUP7
00001b0f: SUB
00001b10: SLT
00001b11: ISZERO
00001b12: PUSH2 0x1b1a
00001b15: JUMPI
00001b16: PUSH1 0x00
00001b18: DUP1
00001b19: REVERT
00001b1a: JUMPDEST
00001b1b: PUSH2 0x1b23
00001b1e: DUP5
00001b1f: PUSH2 0x194f
00001b22: JUMP
00001b23: JUMPDEST
00001b24: SWAP6
00001b25: PUSH1 0x20
00001b27: DUP6
00001b28: ADD
00001b29: CALLDATALOAD
00001b2a: SWAP6
00001b2b: POP
00001b2c: PUSH1 0x40
00001b2e: SWAP1
00001b2f: SWAP5
00001b30: ADD
00001b31: CALLDATALOAD
00001b32: SWAP4
00001b33: SWAP3
00001b34: POP
00001b35: POP
00001b36: POP
00001b37: JUMP
00001b38: JUMPDEST
00001b39: PUSH1 0x00
00001b3b: DUP1
00001b3c: PUSH1 0x20
00001b3e: DUP4
00001b3f: DUP6
00001b40: SUB
00001b41: SLT
00001b42: ISZERO
00001b43: PUSH2 0x1b4b
00001b46: JUMPI
00001b47: PUSH1 0x00
00001b49: DUP1
00001b4a: REVERT
00001b4b: JUMPDEST
00001b4c: DUP3
00001b4d: CALLDATALOAD
00001b4e: PUSH8 0xffffffffffffffff
00001b57: DUP1
00001b58: DUP3
00001b59: GT
00001b5a: ISZERO
00001b5b: PUSH2 0x1b63
00001b5e: JUMPI
00001b5f: PUSH1 0x00
00001b61: DUP1
00001b62: REVERT
00001b63: JUMPDEST
00001b64: DUP2
00001b65: DUP6
00001b66: ADD
00001b67: SWAP2
00001b68: POP
00001b69: DUP6
00001b6a: PUSH1 0x1f
00001b6c: DUP4
00001b6d: ADD
00001b6e: SLT
00001b6f: PUSH2 0x1b77
00001b72: JUMPI
00001b73: PUSH1 0x00
00001b75: DUP1
00001b76: REVERT
00001b77: JUMPDEST
00001b78: DUP2
00001b79: CALLDATALOAD
00001b7a: DUP2
00001b7b: DUP2
00001b7c: GT
00001b7d: ISZERO
00001b7e: PUSH2 0x1b86
00001b81: JUMPI
00001b82: PUSH1 0x00
00001b84: DUP1
00001b85: REVERT
00001b86: JUMPDEST
00001b87: DUP7
00001b88: PUSH1 0x20
00001b8a: DUP3
00001b8b: PUSH1 0x06
00001b8d: SHL
00001b8e: DUP6
00001b8f: ADD
00001b90: ADD
00001b91: GT
00001b92: ISZERO
00001b93: PUSH2 0x1b9b
00001b96: JUMPI
00001b97: PUSH1 0x00
00001b99: DUP1
00001b9a: REVERT
00001b9b: JUMPDEST
00001b9c: PUSH1 0x20
00001b9e: SWAP3
00001b9f: SWAP1
00001ba0: SWAP3
00001ba1: ADD
00001ba2: SWAP7
00001ba3: SWAP2
00001ba4: SWAP6
00001ba5: POP
00001ba6: SWAP1
00001ba7: SWAP4
00001ba8: POP
00001ba9: POP
00001baa: POP
00001bab: POP
00001bac: JUMP
00001bad: JUMPDEST
00001bae: PUSH1 0x00
00001bb0: DUP1
00001bb1: PUSH1 0x00
00001bb3: DUP1
00001bb4: PUSH1 0x40
00001bb6: DUP6
00001bb7: DUP8
00001bb8: SUB
00001bb9: SLT
00001bba: ISZERO
00001bbb: PUSH2 0x1bc3
00001bbe: JUMPI
00001bbf: PUSH1 0x00
00001bc1: DUP1
00001bc2: REVERT
00001bc3: JUMPDEST
00001bc4: DUP5
00001bc5: CALLDATALOAD
00001bc6: PUSH8 0xffffffffffffffff
00001bcf: DUP1
00001bd0: DUP3
00001bd1: GT
00001bd2: ISZERO
00001bd3: PUSH2 0x1bdb
00001bd6: JUMPI
00001bd7: PUSH1 0x00
00001bd9: DUP1
00001bda: REVERT
00001bdb: JUMPDEST
00001bdc: PUSH2 0x1be7
00001bdf: DUP9
00001be0: DUP4
00001be1: DUP10
00001be2: ADD
00001be3: PUSH2 0x1a7e
00001be6: JUMP
00001be7: JUMPDEST
00001be8: SWAP1
00001be9: SWAP7
00001bea: POP
00001beb: SWAP5
00001bec: POP
00001bed: PUSH1 0x20
00001bef: DUP8
00001bf0: ADD
00001bf1: CALLDATALOAD
00001bf2: SWAP2
00001bf3: POP
00001bf4: DUP1
00001bf5: DUP3
00001bf6: GT
00001bf7: ISZERO
00001bf8: PUSH2 0x1c00
00001bfb: JUMPI
00001bfc: PUSH1 0x00
00001bfe: DUP1
00001bff: REVERT
00001c00: JUMPDEST
00001c01: POP
00001c02: PUSH2 0x1c0d
00001c05: DUP8
00001c06: DUP3
00001c07: DUP9
00001c08: ADD
00001c09: PUSH2 0x1a7e
00001c0c: JUMP
00001c0d: JUMPDEST
00001c0e: SWAP6
00001c0f: SWAP9
00001c10: SWAP5
00001c11: SWAP8
00001c12: POP
00001c13: SWAP6
00001c14: POP
00001c15: POP
00001c16: POP
00001c17: POP
00001c18: JUMP
00001c19: JUMPDEST
00001c1a: PUSH32 0x4e487b7100000000000000000000000000000000000000000000000000000000
00001c3b: PUSH1 0x00
00001c3d: MSTORE
00001c3e: PUSH1 0x32
00001c40: PUSH1 0x04
00001c42: MSTORE
00001c43: PUSH1 0x24
00001c45: PUSH1 0x00
00001c47: REVERT
00001c48: JUMPDEST
00001c49: PUSH32 0x4e487b7100000000000000000000000000000000000000000000000000000000
00001c6a: PUSH1 0x00
00001c6c: MSTORE
00001c6d: PUSH1 0x11
00001c6f: PUSH1 0x04
00001c71: MSTORE
00001c72: PUSH1 0x24
00001c74: PUSH1 0x00
00001c76: REVERT
00001c77: JUMPDEST
00001c78: DUP1
00001c79: DUP3
00001c7a: ADD
00001c7b: DUP1
00001c7c: DUP3
00001c7d: GT
00001c7e: ISZERO
00001c7f: PUSH2 0x0bb8
00001c82: JUMPI
00001c83: PUSH2 0x0bb8
00001c86: PUSH2 0x1c48
00001c89: JUMP
00001c8a: JUMPDEST
00001c8b: DUP2
00001c8c: DUP2
00001c8d: SUB
00001c8e: DUP2
00001c8f: DUP2
00001c90: GT
00001c91: ISZERO
00001c92: PUSH2 0x0bb8
00001c95: JUMPI
00001c96: PUSH2 0x0bb8
00001c99: PUSH2 0x1c48
00001c9c: JUMP
00001c9d: JUMPDEST
00001c9e: PUSH32 0x4e487b7100000000000000000000000000000000000000000000000000000000
00001cbf: PUSH1 0x00
00001cc1: MSTORE
00001cc2: PUSH1 0x41
00001cc4: PUSH1 0x04
00001cc6: MSTORE
00001cc7: PUSH1 0x24
00001cc9: PUSH1 0x00
00001ccb: REVERT
00001ccc: JUMPDEST
00001ccd: PUSH1 0x00
00001ccf: PUSH32 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
00001cf0: DUP3
00001cf1: SUB
00001cf2: PUSH2 0x1cfd
00001cf5: JUMPI
00001cf6: PUSH2 0x1cfd
00001cf9: PUSH2 0x1c48
00001cfc: JUMP
00001cfd: JUMPDEST
00001cfe: POP
00001cff: PUSH1 0x01
00001d01: ADD
00001d02: SWAP1
00001d03: JUMP
00001d04: JUMPDEST
00001d05: PUSH1 0x00
00001d07: JUMPDEST
00001d08: DUP4
00001d09: DUP2
00001d0a: LT
00001d0b: ISZERO
00001d0c: PUSH2 0x1d1f
00001d0f: JUMPI
00001d10: DUP2
00001d11: DUP2
00001d12: ADD
00001d13: MLOAD
00001d14: DUP4
00001d15: DUP3
00001d16: ADD
00001d17: MSTORE
00001d18: PUSH1 0x20
00001d1a: ADD
00001d1b: PUSH2 0x1d07
00001d1e: JUMP
00001d1f: JUMPDEST
00001d20: POP
00001d21: POP
00001d22: PUSH1 0x00
00001d24: SWAP2
00001d25: ADD
00001d26: MSTORE
00001d27: JUMP
00001d28: JUMPDEST
00001d29: PUSH1 0x00
00001d2b: DUP2
00001d2c: MLOAD
00001d2d: DUP1
00001d2e: DUP5
00001d2f: MSTORE
00001d30: PUSH2 0x1d40
00001d33: DUP2
00001d34: PUSH1 0x20
00001d36: DUP7
00001d37: ADD
00001d38: PUSH1 0x20
00001d3a: DUP7
00001d3b: ADD
00001d3c: PUSH2 0x1d04
00001d3f: JUMP
00001d40: JUMPDEST
00001d41: PUSH1 0x1f
00001d43: ADD
00001d44: PUSH32 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0
00001d65: AND
00001d66: SWAP3
00001d67: SWAP1
00001d68: SWAP3
00001d69: ADD
00001d6a: PUSH1 0x20
00001d6c: ADD
00001d6d: SWAP3
00001d6e: SWAP2
00001d6f: POP
00001d70: POP
00001d71: JUMP
00001d72: JUMPDEST
00001d73: PUSH1 0x20
00001d75: DUP2
00001d76: MSTORE
00001d77: PUSH1 0x00
00001d79: PUSH2 0x1151
00001d7c: PUSH1 0x20
00001d7e: DUP4
00001d7f: ADD
00001d80: DUP5
00001d81: PUSH2 0x1d28
00001d84: JUMP
00001d85: JUMPDEST
00001d86: PUSH32 0x4e6f20726f7574657220656e726f6c6c656420666f7220646f6d61696e3a2000
00001da7: DUP2
00001da8: MSTORE
00001da9: PUSH1 0x00
00001dab: DUP3
00001dac: MLOAD
00001dad: PUSH2 0x1dbd
00001db0: DUP2
00001db1: PUSH1 0x1f
00001db3: DUP6
00001db4: ADD
00001db5: PUSH1 0x20
00001db7: DUP8
00001db8: ADD
00001db9: PUSH2 0x1d04
00001dbc: JUMP
00001dbd: JUMPDEST
00001dbe: SWAP2
00001dbf: SWAP1
00001dc0: SWAP2
00001dc1: ADD
00001dc2: PUSH1 0x1f
00001dc4: ADD
00001dc5: SWAP3
00001dc6: SWAP2
00001dc7: POP
00001dc8: POP
00001dc9: JUMP
00001dca: JUMPDEST
00001dcb: PUSH1 0x00
00001dcd: DUP1
00001dce: DUP6
00001dcf: DUP6
00001dd0: GT
00001dd1: ISZERO
00001dd2: PUSH2 0x1dda
00001dd5: JUMPI
00001dd6: PUSH1 0x00
00001dd8: DUP1
00001dd9: REVERT
00001dda: JUMPDEST
00001ddb: DUP4
00001ddc: DUP7
00001ddd: GT
00001dde: ISZERO
00001ddf: PUSH2 0x1de7
00001de2: JUMPI
00001de3: PUSH1 0x00
00001de5: DUP1
00001de6: REVERT
00001de7: JUMPDEST
00001de8: POP
00001de9: POP
00001dea: DUP3
00001deb: ADD
00001dec: SWAP4
00001ded: SWAP2
00001dee: SWAP1
00001def: SWAP3
00001df0: SUB
00001df1: SWAP2
00001df2: POP
00001df3: JUMP
00001df4: JUMPDEST
00001df5: DUP1
00001df6: CALLDATALOAD
00001df7: PUSH1 0x20
00001df9: DUP4
00001dfa: LT
00001dfb: ISZERO
00001dfc: PUSH2 0x0bb8
00001dff: JUMPI
00001e00: PUSH32 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
00001e21: PUSH1 0x20
00001e23: DUP5
00001e24: SWAP1
00001e25: SUB
00001e26: PUSH1 0x03
00001e28: SHL
00001e29: SHL
00001e2a: AND
00001e2b: SWAP3
00001e2c: SWAP2
00001e2d: POP
00001e2e: POP
00001e2f: JUMP
00001e30: JUMPDEST
00001e31: DUP4
00001e32: DUP2
00001e33: MSTORE
00001e34: DUP3
00001e35: PUSH1 0x20
00001e37: DUP3
00001e38: ADD
00001e39: MSTORE
00001e3a: PUSH1 0x00
00001e3c: DUP3
00001e3d: MLOAD
00001e3e: PUSH2 0x1e4e
00001e41: DUP2
00001e42: PUSH1 0x40
00001e44: DUP6
00001e45: ADD
00001e46: PUSH1 0x20
00001e48: DUP8
00001e49: ADD
00001e4a: PUSH2 0x1d04
00001e4d: JUMP
00001e4e: JUMPDEST
00001e4f: SWAP2
00001e50: SWAP1
00001e51: SWAP2
00001e52: ADD
00001e53: PUSH1 0x40
00001e55: ADD
00001e56: SWAP5
00001e57: SWAP4
00001e58: POP
00001e59: POP
00001e5a: POP
00001e5b: POP
00001e5c: JUMP
00001e5d: JUMPDEST
00001e5e: PUSH4 0xffffffff
00001e63: DUP7
00001e64: AND
00001e65: DUP2
00001e66: MSTORE
00001e67: DUP5
00001e68: PUSH1 0x20
00001e6a: DUP3
00001e6b: ADD
00001e6c: MSTORE
00001e6d: PUSH1 0xa0
00001e6f: PUSH1 0x40
00001e71: DUP3
00001e72: ADD
00001e73: MSTORE
00001e74: PUSH1 0x00
00001e76: PUSH2 0x1e82
00001e79: PUSH1 0xa0
00001e7b: DUP4
00001e7c: ADD
00001e7d: DUP7
00001e7e: PUSH2 0x1d28
00001e81: JUMP
00001e82: JUMPDEST
00001e83: DUP3
00001e84: DUP2
00001e85: SUB
00001e86: PUSH1 0x60
00001e88: DUP5
00001e89: ADD
00001e8a: MSTORE
00001e8b: PUSH2 0x1e94
00001e8e: DUP2
00001e8f: DUP7
00001e90: PUSH2 0x1d28
00001e93: JUMP
00001e94: JUMPDEST
00001e95: SWAP2
00001e96: POP
00001e97: POP
00001e98: PUSH20 0xffffffffffffffffffffffffffffffffffffffff
00001ead: DUP4
00001eae: AND
00001eaf: PUSH1 0x80
00001eb1: DUP4
00001eb2: ADD
00001eb3: MSTORE
00001eb4: SWAP7
00001eb5: SWAP6
00001eb6: POP
00001eb7: POP
00001eb8: POP
00001eb9: POP
00001eba: POP
00001ebb: POP
00001ebc: JUMP
00001ebd: JUMPDEST
00001ebe: PUSH1 0x00
00001ec0: PUSH1 0x20
00001ec2: DUP3
00001ec3: DUP5
00001ec4: SUB
00001ec5: SLT
00001ec6: ISZERO
00001ec7: PUSH2 0x1ecf
00001eca: JUMPI
00001ecb: PUSH1 0x00
00001ecd: DUP1
00001ece: REVERT
00001ecf: JUMPDEST
00001ed0: POP
00001ed1: MLOAD
00001ed2: SWAP2
00001ed3: SWAP1
00001ed4: POP
00001ed5: JUMP
00001ed6: JUMPDEST
00001ed7: PUSH32 0x4e487b7100000000000000000000000000000000000000000000000000000000
00001ef8: PUSH1 0x00
00001efa: MSTORE
00001efb: PUSH1 0x31
00001efd: PUSH1 0x04
00001eff: MSTORE
00001f00: PUSH1 0x24
00001f02: PUSH1 0x00
00001f04: REVERT
00001f05: JUMPDEST
00001f06: PUSH32 0xffff000000000000000000000000000000000000000000000000000000000000
00001f27: DUP7
00001f28: PUSH1 0xf0
00001f2a: SHL
00001f2b: AND
00001f2c: DUP2
00001f2d: MSTORE
00001f2e: DUP5
00001f2f: PUSH1 0x02
00001f31: DUP3
00001f32: ADD
00001f33: MSTORE
00001f34: DUP4
00001f35: PUSH1 0x22
00001f37: DUP3
00001f38: ADD
00001f39: MSTORE
00001f3a: PUSH32 0xffffffffffffffffffffffffffffffffffffffff000000000000000000000000
00001f5b: DUP4
00001f5c: PUSH1 0x60
00001f5e: SHL
00001f5f: AND
00001f60: PUSH1 0x42
00001f62: DUP3
00001f63: ADD
00001f64: MSTORE
00001f65: PUSH1 0x00
00001f67: DUP3
00001f68: MLOAD
00001f69: PUSH2 0x1f79
00001f6c: DUP2
00001f6d: PUSH1 0x56
00001f6f: DUP6
00001f70: ADD
00001f71: PUSH1 0x20
00001f73: DUP8
00001f74: ADD
00001f75: PUSH2 0x1d04
00001f78: JUMP
00001f79: JUMPDEST
00001f7a: SWAP2
00001f7b: SWAP1
00001f7c: SWAP2
00001f7d: ADD
00001f7e: PUSH1 0x56
00001f80: ADD
00001f81: SWAP7
00001f82: SWAP6
00001f83: POP
00001f84: POP
00001f85: POP
00001f86: POP
00001f87: POP
00001f88: POP
00001f89: JUMP
00001f8a: INVALID
00001f8b: LOG2
00001f8c: PUSH5 0x6970667358
00001f92: UNKNOWN(0x22)
00001f93: SLT
00001f94: KECCAK256
00001f95: UNKNOWN(0xF6)
00001f96: UNKNOWN(0x23)
00001f97: MCOPY
00001f98: UNKNOWN(0xBA)
00001f99: TIMESTAMP
00001f9a: UNKNOWN(0xCD)
00001f9b: SWAP7
00001f9c: MCOPY
00001f9d: UNKNOWN(0xC8)
00001f9e: PUSH26 0x7320b70fa3f71041a56ca31e8577e21f58323505f76e64736f6c
00001fb9: PUSH4 0x43000813
00001fbe: STOP
00001fbf: CALLER

Findings

validated = confirmed for call sinks; sink observed for others
Severity Category Tool Title Confidence Validated Confirmed Details
high auth codex Permissionless initializers let the first caller seize control and mint supply 85 no
view
evidence_json
{
    "evidence": "`initialize`/`setAuthorizedHook` are externally callable with only the OZ `initializer` modifier, which enforces one-time execution but does not authenticate the caller. Some of these initializers also mint to `msg.sender` or rewrite owner/configuration.",
    "locations": [
        "AUDIT_BUNDLE.txt:9360 (contracts/isms/hook/AbstractMessageIdAuthorizedIsm.sol)",
        "AUDIT_BUNDLE.txt:10150 (contracts/hooks/igp/InterchainGasPaymaster.sol)",
        "AUDIT_BUNDLE.txt:12612 (contracts/isms/routing/DomainRoutingIsm.sol)",
        "AUDIT_BUNDLE.txt:12623 (contracts/isms/routing/DomainRoutingIsm.sol)",
        "AUDIT_BUNDLE.txt:13188 (contracts/Mailbox.sol)",
        "AUDIT_BUNDLE.txt:13664 (contracts/middleware/InterchainAccountRouter.sol)",
        "AUDIT_BUNDLE.txt:14255 (contracts/middleware/InterchainQueryRouter.sol)",
        "AUDIT_BUNDLE.txt:14545 (contracts/middleware/liquidity-layer/adapters/CircleBridgeAdapter.sol)",
        "AUDIT_BUNDLE.txt:14862 (contracts/middleware/liquidity-layer/adapters/PortalAdapter.sol)",
        "AUDIT_BUNDLE.txt:15074 (contracts/middleware/liquidity-layer/LiquidityLayerRouter.sol)",
        "AUDIT_BUNDLE.txt:16441 (contracts/token/HypERC20.sol)",
        "AUDIT_BUNDLE.txt:16992 (contracts/token/HypERC721.sol)"
    ],
    "recommendation": "Do not expose public initialization for constructor-deployed instances. Move critical setup into the constructor or gate initialization to the constructor-established owner with a separate one-time guard. If these are meant to be proxy implementations, disable initializers on the implementation and initialize atomically via proxy constructor calldata.",
    "exploit_scenario": "Several production contracts are deployed with constructors but defer critical setup to unrestricted `initializer` functions. If deployment and initialization are not atomic, an attacker can front-run the intended initializer call, become owner, install malicious hooks/ISMs/bridge endpoints, or mint the full initial token/NFT supply to themselves. For example, hijacking `Mailbox.initialize` gives the attacker control over `defaultIsm/defaultHook/requiredHook`, while hijacking `HypERC20.initialize` or `HypERC721.initialize` mints the initial supply to the attacker."
}
high auth codex Anyone can call post-dispatch hooks directly for the current latest message 85 no
view
evidence_json
{
    "evidence": "`AbstractPostDispatchHook.postDispatch` has no caller check. `MerkleTreeHook` and `AbstractMessageIdAuthHook` only verify that the supplied message matches `mailbox.latestDispatchedId()`, which any external caller can satisfy by replaying the just-emitted message bytes.",
    "locations": [
        "AUDIT_BUNDLE.txt:9226 (contracts/hooks/libs/AbstractPostDispatchHook.sol)",
        "AUDIT_BUNDLE.txt:9489 (contracts/hooks/libs/AbstractMessageIdAuthHook.sol)",
        "AUDIT_BUNDLE.txt:10753 (contracts/hooks/MerkleTreeHook.sol)"
    ],
    "recommendation": "Require `msg.sender == address(mailbox)` for hooks whose security depends on mailbox state, or override `postDispatch` in those hooks to enforce mailbox-only access. Add single-use guards per message ID where duplicate execution would be unsafe.",
    "exploit_scenario": "After any legitimate dispatch, the full message bytes are public in the `Dispatch` event and `latestDispatchedId` stays set until the next dispatch. Because `AbstractPostDispatchHook.postDispatch` is permissionless, an attacker can call `MerkleTreeHook.postDispatch` directly and insert the same message ID into the Merkle tree again, corrupting checkpoint state. The same pattern also lets an attacker directly trigger message-id authorization hooks (`ERC5164Hook`/`OPStackHook`) for the current latest message, even if that message did not actually opt into those hooks through mailbox dispatch."
}
medium other detector ETH value transfer possible 40 no no
view
trace_id: 0xb2a2ca4291571cc73421f27f59107c08b13c8c18696ba76e1ccc0531cc23ade9
call_targets: 0x15b5d6b614242b118aa404528a7f3e2ad241e4a4
target_varies: no
classification: constant_target
validation_json
{
    "sink": "CALL",
    "errors": 0,
    "status": "sink_reached",
    "attempts": 1,
    "trace_id": "0xb2a2ca4291571cc73421f27f59107c08b13c8c18696ba76e1ccc0531cc23ade9",
    "confirmed": false,
    "trace_mode": "callTracer",
    "call_targets": [
        "0x15b5d6b614242b118aa404528a7f3e2ad241e4a4"
    ],
    "matched_probe": null,
    "target_varies": false,
    "classification": "constant_target"
}
witness_json
{
    "notes": "heuristic witness; entrypoints are best-effort selectors with zeroed calldata",
    "constraints": [],
    "entrypoints": [
        {
            "calldata": "0xefae508a",
            "selector": "0xefae508a",
            "calldata_variants": [
                "0xefae508a",
                "0xefae508a0000000000000000000000000000000000000000000000000000000000000000"
            ]
        },
        {
            "calldata": "0xf2ed8c53",
            "selector": "0xf2ed8c53",
            "calldata_variants": [
                "0xf2ed8c53",
                "0xf2ed8c530000000000000000000000000000000000000000000000000000000000000000"
            ]
        },
        {
            "calldata": "0xf2fde38b",
            "selector": "0xf2fde38b",
            "calldata_variants": [
                "0xf2fde38b",
                "0xf2fde38b0000000000000000000000000000000000000000000000000000000000000000"
            ]
        },
        {
            "calldata": "0xd5438eae",
            "selector": "0xd5438eae",
            "calldata_variants": [
                "0xd5438eae",
                "0xd5438eae0000000000000000000000000000000000000000000000000000000000000000"
            ]
        },
        {
            "calldata": "0xde523cf3",
            "selector": "0xde523cf3",
            "calldata_variants": [
                "0xde523cf3",
                "0xde523cf30000000000000000000000000000000000000000000000000000000000000000"
            ]
        },
        {
            "calldata": "0xe9198bf9",
            "selector": "0xe9198bf9",
            "calldata_variants": [
                "0xe9198bf9",
                "0xe9198bf90000000000000000000000000000000000000000000000000000000000000000"
            ]
        },
        {
            "calldata": "0x8da5cb5b",
            "selector": "0x8da5cb5b",
            "calldata_variants": [
                "0x8da5cb5b",
                "0x8da5cb5b0000000000000000000000000000000000000000000000000000000000000000"
            ]
        },
        {
            "calldata": "0xb1bd6436",
            "selector": "0xb1bd6436",
            "calldata_variants": [
                "0xb1bd6436",
                "0xb1bd64360000000000000000000000000000000000000000000000000000000000000000"
            ]
        }
    ]
}
evidence_json
{
    "examples": [
        {
            "pc": 5176,
            "opcode": "CALL",
            "returndata_checked": null,
            "value_expression_category": "computed",
            "target_expression_category": "computed"
        },
        {
            "pc": 5577,
            "opcode": "CALL",
            "returndata_checked": null,
            "value_expression_category": "computed",
            "target_expression_category": "computed"
        }
    ],
    "eth_value_calls": 2,
    "guards_detected": [
        {
            "pc": 1949,
            "type": "msg_sender_eq_const",
            "value": "0xffffffffffffffffffffffffffffffffffffffff"
        }
    ]
}
medium other detector Untrusted CALL target/value reachable 45 no no
view
trace_id: 0xb2a2ca4291571cc73421f27f59107c08b13c8c18696ba76e1ccc0531cc23ade9
call_targets: 0x15b5d6b614242b118aa404528a7f3e2ad241e4a4
target_varies: no
classification: constant_target
validation_json
{
    "sink": "CALL",
    "errors": 0,
    "status": "sink_reached",
    "attempts": 1,
    "trace_id": "0xb2a2ca4291571cc73421f27f59107c08b13c8c18696ba76e1ccc0531cc23ade9",
    "confirmed": false,
    "trace_mode": "callTracer",
    "call_targets": [
        "0x15b5d6b614242b118aa404528a7f3e2ad241e4a4"
    ],
    "matched_probe": null,
    "target_varies": false,
    "classification": "constant_target"
}
witness_json
{
    "notes": "heuristic witness; entrypoints are best-effort selectors with zeroed calldata",
    "constraints": [],
    "entrypoints": [
        {
            "calldata": "0xefae508a",
            "selector": "0xefae508a",
            "calldata_variants": [
                "0xefae508a",
                "0xefae508a0000000000000000000000000000000000000000000000000000000000000000"
            ]
        },
        {
            "calldata": "0xf2ed8c53",
            "selector": "0xf2ed8c53",
            "calldata_variants": [
                "0xf2ed8c53",
                "0xf2ed8c530000000000000000000000000000000000000000000000000000000000000000"
            ]
        },
        {
            "calldata": "0xf2fde38b",
            "selector": "0xf2fde38b",
            "calldata_variants": [
                "0xf2fde38b",
                "0xf2fde38b0000000000000000000000000000000000000000000000000000000000000000"
            ]
        },
        {
            "calldata": "0xd5438eae",
            "selector": "0xd5438eae",
            "calldata_variants": [
                "0xd5438eae",
                "0xd5438eae0000000000000000000000000000000000000000000000000000000000000000"
            ]
        },
        {
            "calldata": "0xde523cf3",
            "selector": "0xde523cf3",
            "calldata_variants": [
                "0xde523cf3",
                "0xde523cf30000000000000000000000000000000000000000000000000000000000000000"
            ]
        },
        {
            "calldata": "0xe9198bf9",
            "selector": "0xe9198bf9",
            "calldata_variants": [
                "0xe9198bf9",
                "0xe9198bf90000000000000000000000000000000000000000000000000000000000000000"
            ]
        },
        {
            "calldata": "0x8da5cb5b",
            "selector": "0x8da5cb5b",
            "calldata_variants": [
                "0x8da5cb5b",
                "0x8da5cb5b0000000000000000000000000000000000000000000000000000000000000000"
            ]
        },
        {
            "calldata": "0xb1bd6436",
            "selector": "0xb1bd6436",
            "calldata_variants": [
                "0xb1bd6436",
                "0xb1bd64360000000000000000000000000000000000000000000000000000000000000000"
            ]
        }
    ]
}
evidence_json
{
    "examples": [
        {
            "pc": 5176,
            "opcode": "CALL",
            "returndata_checked": null,
            "value_expression_category": "computed",
            "target_expression_category": "computed"
        },
        {
            "pc": 5577,
            "opcode": "CALL",
            "returndata_checked": null,
            "value_expression_category": "computed",
            "target_expression_category": "computed"
        }
    ],
    "call_count": 2,
    "guards_detected": [
        {
            "pc": 1949,
            "type": "msg_sender_eq_const",
            "value": "0xffffffffffffffffffffffffffffffffffffffff"
        }
    ],
    "untrusted_call_count": 2
}
low other codex DestinationRecipientRoutingHook quotes the wrong hook for recipient-specific routes 65 no
view
evidence_json
{
    "evidence": "`DestinationRecipientRoutingHook._postDispatch` consults `customHooks[destination][recipient]`, but inherited `DomainRoutingHook._quoteDispatch` only calls `_getConfiguredHook(message)`, which is destination-only and never checks the recipient override map.",
    "locations": [
        "AUDIT_BUNDLE.txt:11186 (contracts/hooks/routing/DomainRoutingHook.sol)",
        "AUDIT_BUNDLE.txt:11238 (contracts/hooks/routing/DestinationRecipientRoutingHook.sol)"
    ],
    "recommendation": "Override `_quoteDispatch` in `DestinationRecipientRoutingHook` so it resolves the same hook that `_postDispatch` will actually call, including recipient-specific overrides.",
    "exploit_scenario": "If the owner configures a `customHooks[destination][recipient]`, dispatch execution will route to that custom hook, but fee quoting still uses the destination-level hook from `DomainRoutingHook`. Users relying on `quoteDispatch` can underpay and have dispatches revert, making recipient-specific routes unusable unless callers manually overpay."
}