--- a/net/minecraft/world/inventory/MerchantMenu.java
+++ b/net/minecraft/world/inventory/MerchantMenu.java
@@ -9,9 +9,12 @@
 import net.minecraft.world.entity.player.Player;
 import net.minecraft.world.item.ItemStack;
 import net.minecraft.world.item.trading.Merchant;
+import net.minecraft.world.item.trading.MerchantOffer;
 import net.minecraft.world.item.trading.MerchantOffers;
+import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftInventoryView; // CraftBukkit
 
 public class MerchantMenu extends AbstractContainerMenu {
+
     protected static final int PAYMENT1_SLOT = 0;
     protected static final int PAYMENT2_SLOT = 1;
     protected static final int RESULT_SLOT = 2;
@@ -29,6 +32,19 @@
     private boolean showProgressBar;
     private boolean canRestock;
 
+    // CraftBukkit start
+    private CraftInventoryView bukkitEntity = null;
+    private Inventory player;
+
+    @Override
+    public CraftInventoryView getBukkitView() {
+        if (this.bukkitEntity == null) {
+            this.bukkitEntity = new CraftInventoryView(this.player.player.getBukkitEntity(), new org.bukkit.craftbukkit.v1_19_R1.inventory.CraftInventoryMerchant(this.trader, this.tradeContainer), this);
+        }
+        return this.bukkitEntity;
+    }
+    // CraftBukkit end
+
     public MerchantMenu(int syncId, Inventory playerInventory) {
         this(syncId, playerInventory, new ClientSideMerchant(playerInventory.player));
     }
@@ -40,15 +56,18 @@
         this.addSlot(new Slot(this.tradeContainer, 0, 136, 37));
         this.addSlot(new Slot(this.tradeContainer, 1, 162, 37));
         this.addSlot(new MerchantResultSlot(playerInventory.player, merchant, this.tradeContainer, 2, 220, 37));
+        this.player = playerInventory; // CraftBukkit - save player
 
-        for(int i = 0; i < 3; ++i) {
-            for(int j = 0; j < 9; ++j) {
-                this.addSlot(new Slot(playerInventory, j + i * 9 + 9, 108 + j * 18, 84 + i * 18));
+        int j;
+
+        for (j = 0; j < 3; ++j) {
+            for (int k = 0; k < 9; ++k) {
+                this.addSlot(new Slot(playerInventory, k + j * 9 + 9, 108 + k * 18, 84 + j * 18));
             }
         }
 
-        for(int k = 0; k < 9; ++k) {
-            this.addSlot(new Slot(playerInventory, k, 108 + k * 18, 142));
+        for (j = 0; j < 9; ++j) {
+            this.addSlot(new Slot(playerInventory, j, 108 + j * 18, 142));
         }
 
     }
@@ -107,49 +126,68 @@
 
     @Override
     public ItemStack quickMoveStack(Player player, int index) {
-        ItemStack itemStack = ItemStack.EMPTY;
-        Slot slot = this.slots.get(index);
+        ItemStack itemstack = ItemStack.EMPTY;
+        Slot slot = (Slot) this.slots.get(index);
+
         if (slot != null && slot.hasItem()) {
-            ItemStack itemStack2 = slot.getItem();
-            itemStack = itemStack2.copy();
+            ItemStack itemstack1 = slot.getItem();
+
+            itemstack = itemstack1.copy();
             if (index == 2) {
-                if (!this.moveItemStackTo(itemStack2, 3, 39, true)) {
+                if (!this.moveItemStackTo(itemstack1, 3, 39, true, true)) { // Paper
                     return ItemStack.EMPTY;
                 }
 
-                slot.onQuickCraft(itemStack2, itemStack);
-                this.playTradeSound();
+                // slot.onQuickCraft(itemstack1, itemstack); // Paper - moved to after the non-check moveItemStackTo call
+                // this.playTradeSound();
             } else if (index != 0 && index != 1) {
                 if (index >= 3 && index < 30) {
-                    if (!this.moveItemStackTo(itemStack2, 30, 39, false)) {
+                    if (!this.moveItemStackTo(itemstack1, 30, 39, false)) {
                         return ItemStack.EMPTY;
                     }
-                } else if (index >= 30 && index < 39 && !this.moveItemStackTo(itemStack2, 3, 30, false)) {
+                } else if (index >= 30 && index < 39 && !this.moveItemStackTo(itemstack1, 3, 30, false)) {
                     return ItemStack.EMPTY;
                 }
-            } else if (!this.moveItemStackTo(itemStack2, 3, 39, false)) {
+            } else if (!this.moveItemStackTo(itemstack1, 3, 39, false)) {
                 return ItemStack.EMPTY;
             }
 
-            if (itemStack2.isEmpty()) {
+            if (index != 2) { // Paper - moved down for slot 2
+            if (itemstack1.isEmpty()) {
                 slot.set(ItemStack.EMPTY);
             } else {
                 slot.setChanged();
             }
 
-            if (itemStack2.getCount() == itemStack.getCount()) {
+            if (itemstack1.getCount() == itemstack.getCount()) {
                 return ItemStack.EMPTY;
             }
 
-            slot.onTake(player, itemStack2);
+            slot.onTake(player, itemstack1);
+            } // Paper start - handle slot 2
+            if (index == 2) { // is merchant result slot
+                slot.onTake(player, itemstack1);
+                if (itemstack1.isEmpty()) {
+                    slot.set(ItemStack.EMPTY);
+                    return ItemStack.EMPTY;
+                }
+
+                this.moveItemStackTo(itemstack1, 3, 39, true, false); // This should always succeed because it's checked above
+
+                slot.onQuickCraft(itemstack1, itemstack);
+                this.playTradeSound();
+                slot.set(ItemStack.EMPTY); // itemstack1 should ALWAYS be empty
+            }
+            // Paper end
         }
 
-        return itemStack;
+        return itemstack;
     }
 
     private void playTradeSound() {
-        if (!this.trader.isClientSide()) {
-            Entity entity = (Entity)this.trader;
+        if (!this.trader.isClientSide() && this.trader instanceof Entity) { // CraftBukkit - SPIGOT-5035
+            Entity entity = (Entity) this.trader;
+
             entity.getLevel().playLocalSound(entity.getX(), entity.getY(), entity.getZ(), this.trader.getNotifyTradeSound(), SoundSource.NEUTRAL, 1.0F, 1.0F, false);
         }
 
@@ -158,21 +196,24 @@
     @Override
     public void removed(Player player) {
         super.removed(player);
-        this.trader.setTradingPlayer((Player)null);
+        this.trader.setTradingPlayer((Player) null);
         if (!this.trader.isClientSide()) {
-            if (!player.isAlive() || player instanceof ServerPlayer && ((ServerPlayer)player).hasDisconnected()) {
-                ItemStack itemStack = this.tradeContainer.removeItemNoUpdate(0);
-                if (!itemStack.isEmpty()) {
-                    player.drop(itemStack, false);
+            if (player.isAlive() && (!(player instanceof ServerPlayer) || !((ServerPlayer) player).hasDisconnected())) {
+                if (player instanceof ServerPlayer) {
+                    player.getInventory().placeItemBackInInventory(this.tradeContainer.removeItemNoUpdate(0));
+                    player.getInventory().placeItemBackInInventory(this.tradeContainer.removeItemNoUpdate(1));
                 }
+            } else {
+                ItemStack itemstack = this.tradeContainer.removeItemNoUpdate(0);
 
-                itemStack = this.tradeContainer.removeItemNoUpdate(1);
-                if (!itemStack.isEmpty()) {
-                    player.drop(itemStack, false);
+                if (!itemstack.isEmpty()) {
+                    player.drop(itemstack, false);
+                }
+
+                itemstack = this.tradeContainer.removeItemNoUpdate(1);
+                if (!itemstack.isEmpty()) {
+                    player.drop(itemstack, false);
                 }
-            } else if (player instanceof ServerPlayer) {
-                player.getInventory().placeItemBackInInventory(this.tradeContainer.removeItemNoUpdate(0));
-                player.getInventory().placeItemBackInInventory(this.tradeContainer.removeItemNoUpdate(1));
             }
 
         }
@@ -180,29 +221,33 @@
 
     public void tryMoveItems(int recipeIndex) {
         if (this.getOffers().size() > recipeIndex) {
-            ItemStack itemStack = this.tradeContainer.getItem(0);
-            if (!itemStack.isEmpty()) {
-                if (!this.moveItemStackTo(itemStack, 3, 39, true)) {
+            ItemStack itemstack = this.tradeContainer.getItem(0);
+
+            if (!itemstack.isEmpty()) {
+                if (!this.moveItemStackTo(itemstack, 3, 39, true)) {
                     return;
                 }
 
-                this.tradeContainer.setItem(0, itemStack);
+                this.tradeContainer.setItem(0, itemstack);
             }
 
-            ItemStack itemStack2 = this.tradeContainer.getItem(1);
-            if (!itemStack2.isEmpty()) {
-                if (!this.moveItemStackTo(itemStack2, 3, 39, true)) {
+            ItemStack itemstack1 = this.tradeContainer.getItem(1);
+
+            if (!itemstack1.isEmpty()) {
+                if (!this.moveItemStackTo(itemstack1, 3, 39, true)) {
                     return;
                 }
 
-                this.tradeContainer.setItem(1, itemStack2);
+                this.tradeContainer.setItem(1, itemstack1);
             }
 
             if (this.tradeContainer.getItem(0).isEmpty() && this.tradeContainer.getItem(1).isEmpty()) {
-                ItemStack itemStack3 = this.getOffers().get(recipeIndex).getCostA();
-                this.moveFromInventoryToPaymentSlot(0, itemStack3);
-                ItemStack itemStack4 = this.getOffers().get(recipeIndex).getCostB();
-                this.moveFromInventoryToPaymentSlot(1, itemStack4);
+                ItemStack itemstack2 = ((MerchantOffer) this.getOffers().get(recipeIndex)).getCostA();
+
+                this.moveFromInventoryToPaymentSlot(0, itemstack2);
+                ItemStack itemstack3 = ((MerchantOffer) this.getOffers().get(recipeIndex)).getCostB();
+
+                this.moveFromInventoryToPaymentSlot(1, itemstack3);
             }
 
         }
@@ -210,18 +255,20 @@
 
     private void moveFromInventoryToPaymentSlot(int slot, ItemStack stack) {
         if (!stack.isEmpty()) {
-            for(int i = 3; i < 39; ++i) {
-                ItemStack itemStack = this.slots.get(i).getItem();
-                if (!itemStack.isEmpty() && ItemStack.isSameItemSameTags(stack, itemStack)) {
-                    ItemStack itemStack2 = this.tradeContainer.getItem(slot);
-                    int j = itemStack2.isEmpty() ? 0 : itemStack2.getCount();
-                    int k = Math.min(stack.getMaxStackSize() - j, itemStack.getCount());
-                    ItemStack itemStack3 = itemStack.copy();
-                    int l = j + k;
-                    itemStack.shrink(k);
-                    itemStack3.setCount(l);
-                    this.tradeContainer.setItem(slot, itemStack3);
-                    if (l >= stack.getMaxStackSize()) {
+            for (int j = 3; j < 39; ++j) {
+                ItemStack itemstack1 = ((Slot) this.slots.get(j)).getItem();
+
+                if (!itemstack1.isEmpty() && ItemStack.isSameItemSameTags(stack, itemstack1)) {
+                    ItemStack itemstack2 = this.tradeContainer.getItem(slot);
+                    int k = itemstack2.isEmpty() ? 0 : itemstack2.getCount();
+                    int l = Math.min(stack.getMaxStackSize() - k, itemstack1.getCount());
+                    ItemStack itemstack3 = itemstack1.copy();
+                    int i1 = k + l;
+
+                    itemstack1.shrink(l);
+                    itemstack3.setCount(i1);
+                    this.tradeContainer.setItem(slot, itemstack3);
+                    if (i1 >= stack.getMaxStackSize()) {
                         break;
                     }
                 }
