Queued transfers can become stuck on the source chain if Transceiver instructions are encoded in the incorrect order
In the case of multiple Transceivers, the current logic expects that a sender encodes Transceiver instructions in order of increasing Transceiver registration index, as validated in `TransceiverStructs::parseTransceiverInstructions`. Under normal circumstances, this logic works as expected, and the transaction fails when the user packs transceiver instructions in the incorrect order.\\n```\\n/* snip */\\nfor (uint256 i = 0; i < instructionsLength; i++) {\\n    TransceiverInstruction memory instruction;\\n    (instruction, offset) = parseTransceiverInstructionUnchecked(encoded, offset);\\n\\n    uint8 instructionIndex = instruction.index;\\n\\n    // The instructions passed in have to be strictly increasing in terms of transceiver index\\n    if (i != 0 && instructionIndex <= lastIndex) {\\n        revert UnorderedInstructions();\\n    }\\n    lastIndex = instructionIndex;\\n\\n    instructions[instructionIndex] = instruction;\\n}\\n/* snip */\\n```\\n\\nHowever, this requirement on the order of Transceiver indices is not checked when transfers are initially queued for delayed execution. As a result, a transaction where this is the case will fail when the user calls `NttManager::completeOutboundQueuedTransfer` to execute a queued transfer.
When the transfer amount exceeds the current outbound capacity, verify the Transceiver instructions are ordered correctly before adding a message to the list of queued transfers.
The sender's funds are transferred to the NTT Manager when messages are queued. However, this queued message can never be executed if the Transceiver indices are incorrectly ordered and, as a result, the user funds remain stuck in the NTT Manager.\\nProof of Concept: Run the following test:\\n```\\ncontract TestWrongTransceiverOrder is Test, INttManagerEvents, IRateLimiterEvents {\\n    NttManager nttManagerChain1;\\n    NttManager nttManagerChain2;\\n\\n    using TrimmedAmountLib for uint256;\\n    using TrimmedAmountLib for TrimmedAmount;\\n\\n    uint16 constant chainId1 = 7;\\n    uint16 constant chainId2 = 100;\\n    uint8 constant FAST_CONSISTENCY_LEVEL = 200;\\n    uint256 constant GAS_LIMIT = 500000;\\n\\n    uint16 constant SENDING_CHAIN_ID = 1;\\n    uint256 constant DEVNET_GUARDIAN_PK =\\n        0xcfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0;\\n    WormholeSimulator guardian;\\n    uint256 initialBlockTimestamp;\\n\\n    WormholeTransceiver wormholeTransceiverChain1;\\n    WormholeTransceiver wormholeTransceiver2Chain1;\\n\\n    WormholeTransceiver wormholeTransceiverChain2;\\n    address userA = address(0x123);\\n    address userB = address(0x456);\\n    address userC = address(0x789);\\n    address userD = address(0xABC);\\n\\n    address relayer = address(0x28D8F1Be96f97C1387e94A53e00eCcFb4E75175a);\\n    IWormhole wormhole = IWormhole(0x706abc4E45D419950511e474C7B9Ed348A4a716c);\\n\\n    function setUp() public {\\n        string memory url = "https://goerli.blockpi.network/v1/rpc/public";\\n        vm.createSelectFork(url);\\n        initialBlockTimestamp = vm.getBlockTimestamp();\\n\\n        guardian = new WormholeSimulator(address(wormhole), DEVNET_GUARDIAN_PK);\\n\\n        vm.chainId(chainId1);\\n        DummyToken t1 = new DummyToken();\\n        NttManager implementation =\\n            new MockNttManagerContract(address(t1), INttManager.Mode.LOCKING, chainId1, 1 days);\\n\\n        nttManagerChain1 =\\n            MockNttManagerContract(address(new ERC1967Proxy(address(implementation), "")));\\n        nttManagerChain1.initialize();\\n\\n        WormholeTransceiver wormholeTransceiverChain1Implementation = new MockWormholeTransceiverContract(\\n            address(nttManagerChain1),\\n            address(wormhole),\\n            address(relayer),\\n            address(0x0),\\n            FAST_CONSISTENCY_LEVEL,\\n            GAS_LIMIT\\n        );\\n        wormholeTransceiverChain1 = MockWormholeTransceiverContract(\\n            address(new ERC1967Proxy(address(wormholeTransceiverChain1Implementation), ""))\\n        );\\n\\n        WormholeTransceiver wormholeTransceiverChain1Implementation2 = new MockWormholeTransceiverContract(\\n            address(nttManagerChain1),\\n            address(wormhole),\\n            address(relayer),\\n            address(0x0),\\n            FAST_CONSISTENCY_LEVEL,\\n            GAS_LIMIT\\n        );\\n        wormholeTransceiver2Chain1 = MockWormholeTransceiverContract(\\n            address(new ERC1967Proxy(address(wormholeTransceiverChain1Implementation2), ""))\\n        );\\n\\n\\n        // Actually initialize properly now\\n        wormholeTransceiverChain1.initialize();\\n        wormholeTransceiver2Chain1.initialize();\\n\\n\\n        nttManagerChain1.setTransceiver(address(wormholeTransceiverChain1));\\n        nttManagerChain1.setTransceiver(address(wormholeTransceiver2Chain1));\\n        nttManagerChain1.setOutboundLimit(type(uint64).max);\\n        nttManagerChain1.setInboundLimit(type(uint64).max, chainId2);\\n\\n        // Chain 2 setup\\n        vm.chainId(chainId2);\\n        DummyToken t2 = new DummyTokenMintAndBurn();\\n        NttManager implementationChain2 =\\n            new MockNttManagerContract(address(t2), INttManager.Mode.BURNING, chainId2, 1 days);\\n\\n        nttManagerChain2 =\\n            MockNttManagerContract(address(new ERC1967Proxy(address(implementationChain2), "")));\\n        nttManagerChain2.initialize();\\n\\n        WormholeTransceiver wormholeTransceiverChain2Implementation = new MockWormholeTransceiverContract(\\n            address(nttManagerChain2),\\n            address(wormhole),\\n            address(relayer),\\n            address(0x0),\\n            FAST_CONSISTENCY_LEVEL,\\n            GAS_LIMIT\\n        );\\n\\n        wormholeTransceiverChain2 = MockWormholeTransceiverContract(\\n            address(new ERC1967Proxy(address(wormholeTransceiverChain2Implementation), ""))\\n        );\\n        wormholeTransceiverChain2.initialize();\\n\\n        nttManagerChain2.setTransceiver(address(wormholeTransceiverChain2));\\n        nttManagerChain2.setOutboundLimit(type(uint64).max);\\n        nttManagerChain2.setInboundLimit(type(uint64).max, chainId1);\\n\\n        // Register peer contracts for the nttManager and transceiver. Transceivers and nttManager each have the concept of peers here.\\n        nttManagerChain1.setPeer(chainId2, bytes32(uint256(uint160(address(nttManagerChain2)))), 9);\\n        nttManagerChain2.setPeer(chainId1, bytes32(uint256(uint160(address(nttManagerChain1)))), 7);\\n\\n        // Set peers for the transceivers\\n        wormholeTransceiverChain1.setWormholePeer(\\n            chainId2, bytes32(uint256(uint160(address(wormholeTransceiverChain2))))\\n        );\\n\\n       wormholeTransceiver2Chain1.setWormholePeer(\\n            chainId2, bytes32(uint256(uint160(address(wormholeTransceiverChain2))))\\n        );\\n\\n        wormholeTransceiverChain2.setWormholePeer(\\n            chainId1, bytes32(uint256(uint160(address(wormholeTransceiverChain1))))\\n        );\\n\\n        require(nttManagerChain1.getThreshold() != 0, "Threshold is zero with active transceivers");\\n\\n        // Actually set it\\n        nttManagerChain1.setThreshold(2);\\n        nttManagerChain2.setThreshold(1);\\n    }\\n\\n    function testWrongTransceiverOrder() external {\\n        vm.chainId(chainId1);\\n\\n        // Setting up the transfer\\n        DummyToken token1 = DummyToken(nttManagerChain1.token());\\n        uint8 decimals = token1.decimals();\\n\\n        token1.mintDummy(address(userA), 5 * 10 ** decimals);\\n        uint256 outboundLimit = 4 * 10 ** decimals;\\n        nttManagerChain1.setOutboundLimit(outboundLimit);\\n\\n        vm.startPrank(userA);\\n\\n        uint256 transferAmount = 5 * 10 ** decimals;\\n        token1.approve(address(nttManagerChain1), transferAmount);\\n\\n        // transfer with shouldQueue == true\\n        uint64 qSeq = nttManagerChain1.transfer(\\n            transferAmount, chainId2, toWormholeFormat(userB), true, encodeTransceiverInstructionsJumbled(true)\\n        );\\n\\n        assertEq(qSeq, 0);\\n        IRateLimiter.OutboundQueuedTransfer memory qt = nttManagerChain1.getOutboundQueuedTransfer(0);\\n        assertEq(qt.amount.getAmount(), transferAmount.trim(decimals, decimals).getAmount());\\n        assertEq(qt.recipientChain, chainId2);\\n        assertEq(qt.recipient, toWormholeFormat(userB));\\n        assertEq(qt.txTimestamp, initialBlockTimestamp);\\n\\n        // assert that the contract also locked funds from the user\\n        assertEq(token1.balanceOf(address(userA)), 0);\\n        assertEq(token1.balanceOf(address(nttManagerChain1)), transferAmount);\\n\\n         // elapse rate limit duration - 1\\n        uint256 durationElapsedTime = initialBlockTimestamp + nttManagerChain1.rateLimitDuration();\\n\\n        vm.warp(durationElapsedTime);\\n\\n        vm.expectRevert(0x71f23ef2); //UnorderedInstructions() selector\\n        nttManagerChain1.completeOutboundQueuedTransfer(0);\\n    }\\n\\n    // Encode an instruction for each of the relayers\\n    function encodeTransceiverInstructionsJumbled(bool relayer_off) public view returns (bytes memory) {\\n        WormholeTransceiver.WormholeTransceiverInstruction memory instruction =\\n            IWormholeTransceiver.WormholeTransceiverInstruction(relayer_off);\\n\\n        bytes memory encodedInstructionWormhole =\\n            wormholeTransceiverChain1.encodeWormholeTransceiverInstruction(instruction);\\n\\n        TransceiverStructs.TransceiverInstruction memory TransceiverInstruction1 =\\n        TransceiverStructs.TransceiverInstruction({index: 0, payload: encodedInstructionWormhole});\\n        TransceiverStructs.TransceiverInstruction memory TransceiverInstruction2 =\\n        TransceiverStructs.TransceiverInstruction({index: 1, payload: encodedInstructionWormhole});\\n\\n        TransceiverStructs.TransceiverInstruction[] memory TransceiverInstructions =\\n            new TransceiverStructs.TransceiverInstruction[](2);\\n\\n        TransceiverInstructions[0] = TransceiverInstruction2;\\n        TransceiverInstructions[1] = TransceiverInstruction1;\\n\\n        return TransceiverStructs.encodeTransceiverInstructions(TransceiverInstructions);\\n    }\\n}\\n```\\n
```\\n/* snip */\\nfor (uint256 i = 0; i < instructionsLength; i++) {\\n    TransceiverInstruction memory instruction;\\n    (instruction, offset) = parseTransceiverInstructionUnchecked(encoded, offset);\\n\\n    uint8 instructionIndex = instruction.index;\\n\\n    // The instructions passed in have to be strictly increasing in terms of transceiver index\\n    if (i != 0 && instructionIndex <= lastIndex) {\\n        revert UnorderedInstructions();\\n    }\\n    lastIndex = instructionIndex;\\n\\n    instructions[instructionIndex] = instruction;\\n}\\n/* snip */\\n```\\n