Validation is missing for tokenA in `SwapExchange::calculateMultiSwap()`
The protocol supports claiming a chain of swaps and the function `SwapExchange::calculateMultiSwap()` is used to do some calculations including the amount of tokenA that can be received for a given amount of tokenB. Looking at the implementation, the protocol does not validate that the tokenA of the last swap in the chain is actually the same as the tokenA of `multiClaimInput`. Because this view function is supposed to be used by the frontend to 'preview' the result of a `MultiSwap`, this does not imply a direct security risk but can lead to unexpected results. (It is notable that the actual swap function `SwapExchange::_claimMultiSwap()` implemented a proper validation.)\\n```\\nSwapExchange.sol\\n    function calculateMultiSwap(SwapUtils.MultiClaimInput calldata multiClaimInput) external view returns (SwapUtils.SwapCalculation memory) {\\n        uint256 swapIdCount = multiClaimInput.swapIds.length;\\n        if (swapIdCount == 0 || swapIdCount > _maxHops) revert Errors.InvalidMultiClaimSwapCount(_maxHops, swapIdCount);\\n        if (swapIdCount == 1) {\\n            SwapUtils.Swap memory swap = swaps[multiClaimInput.swapIds[0]];\\n            return SwapUtils._calculateSwapNetB(swap, multiClaimInput.amountB, _feeValue, _feeDenominator, _fixedFee);\\n        }\\n        uint256 matchAmount = multiClaimInput.amountB;\\n        address matchToken = multiClaimInput.tokenB;\\n        uint256 swapId;\\n        bool complete = true;\\n        for (uint256 i = 0; i < swapIdCount; i++) {\\n            swapId = multiClaimInput.swapIds[i];\\n            SwapUtils.Swap memory swap = swaps[swapId];\\n            if (swap.tokenB != matchToken) revert Errors.NonMatchingToken();\\n            if (swap.amountB < matchAmount) revert Errors.NonMatchingAmount();\\n            if (matchAmount < swap.amountB) {\\n                if (!swap.isPartial) revert Errors.NotPartialSwap();\\n                matchAmount = MathUtils._mulDiv(swap.amountA, matchAmount, swap.amountB);\\n                complete = complete && false;\\n            }\\n            else {\\n                matchAmount = swap.amountA;\\n            }\\n            matchToken = swap.tokenA;\\n        }\\n        (uint8 feeType,) = _calculateFeeType(multiClaimInput.tokenA, multiClaimInput.tokenB);//@audit-issue no validation matchToken == multiClaimInput.tokenA\\n        uint256 fee = FeeUtils._calculateFees(matchAmount, multiClaimInput.amountB, feeType, swapIdCount, _feeValue, _feeDenominator, _fixedFee);\\n        SwapUtils.SwapCalculation memory calculation;\\n        calculation.amountA = matchAmount;\\n        calculation.amountB = multiClaimInput.amountB;\\n        calculation.fee = fee;\\n        calculation.feeType = feeType;\\n        calculation.isTokenBNative = multiClaimInput.tokenB == Constants.NATIVE_ADDRESS;\\n        calculation.isComplete = complete;\\n        calculation.nativeSendAmount = SwapUtils._calculateNativeSendAmount(calculation.amountB, calculation.fee, calculation.feeType, calculation.isTokenBNative);\\n        return calculation;\\n    }\\n```\\n
Add a validation that the tokenA of the last swap in the chain is the same as the tokenA of `multiClaimInput`.
The function will return an incorrect swap calculation result if the last swap in the chain has a different tokenA than the tokenA of `multiClaimInput` and it can lead to unexpected results.
```\\nSwapExchange.sol\\n    function calculateMultiSwap(SwapUtils.MultiClaimInput calldata multiClaimInput) external view returns (SwapUtils.SwapCalculation memory) {\\n        uint256 swapIdCount = multiClaimInput.swapIds.length;\\n        if (swapIdCount == 0 || swapIdCount > _maxHops) revert Errors.InvalidMultiClaimSwapCount(_maxHops, swapIdCount);\\n        if (swapIdCount == 1) {\\n            SwapUtils.Swap memory swap = swaps[multiClaimInput.swapIds[0]];\\n            return SwapUtils._calculateSwapNetB(swap, multiClaimInput.amountB, _feeValue, _feeDenominator, _fixedFee);\\n        }\\n        uint256 matchAmount = multiClaimInput.amountB;\\n        address matchToken = multiClaimInput.tokenB;\\n        uint256 swapId;\\n        bool complete = true;\\n        for (uint256 i = 0; i < swapIdCount; i++) {\\n            swapId = multiClaimInput.swapIds[i];\\n            SwapUtils.Swap memory swap = swaps[swapId];\\n            if (swap.tokenB != matchToken) revert Errors.NonMatchingToken();\\n            if (swap.amountB < matchAmount) revert Errors.NonMatchingAmount();\\n            if (matchAmount < swap.amountB) {\\n                if (!swap.isPartial) revert Errors.NotPartialSwap();\\n                matchAmount = MathUtils._mulDiv(swap.amountA, matchAmount, swap.amountB);\\n                complete = complete && false;\\n            }\\n            else {\\n                matchAmount = swap.amountA;\\n            }\\n            matchToken = swap.tokenA;\\n        }\\n        (uint8 feeType,) = _calculateFeeType(multiClaimInput.tokenA, multiClaimInput.tokenB);//@audit-issue no validation matchToken == multiClaimInput.tokenA\\n        uint256 fee = FeeUtils._calculateFees(matchAmount, multiClaimInput.amountB, feeType, swapIdCount, _feeValue, _feeDenominator, _fixedFee);\\n        SwapUtils.SwapCalculation memory calculation;\\n        calculation.amountA = matchAmount;\\n        calculation.amountB = multiClaimInput.amountB;\\n        calculation.fee = fee;\\n        calculation.feeType = feeType;\\n        calculation.isTokenBNative = multiClaimInput.tokenB == Constants.NATIVE_ADDRESS;\\n        calculation.isComplete = complete;\\n        calculation.nativeSendAmount = SwapUtils._calculateNativeSendAmount(calculation.amountB, calculation.fee, calculation.feeType, calculation.isTokenBNative);\\n        return calculation;\\n    }\\n```\\n