HIGH severity: Users may lose value when transferring ERVault tokens cross-chain. **Description:** Both the `VaultV0` and `VaultV3` ERC-4626 tokens are designed to be transferable across chains and therefore implement the LayerZero cross-chain OFT standard.

When a token is transferred cross-chain, the `_debit` function is called to determine how the token should be "removed"...

Vulnerable code:
function _debit(address _from, uint256 _amountLD, uint256 _minAmountLD, uint32 _dstEid) internal virtual override returns (uint256 amountSentLD, uint256 amountReceivedLD) {
    (amountSentLD, amountReceivedLD) = _debitView(_amountLD, _minAmountLD, _dstEid);
    _burn(_from, amountSentLD);
}

function _credit(address _to, uint256 _amountLD, uint32) internal virtual override returns (uint256 amountReceivedLD) {
    if (_to == address(0x0)) _to = address(0xdead);
    _mint(_to, _amountLD);
    return _amountLD;
}

function test_vaultV0_xchain_transfer_affects_vault_exchange_rate() public {
    deal(address(asset), DEPOSITOR, 2e18);

    // 1. Bob and Alice both participate in the vault
    vm.startPrank(DEPOSITOR);
    asset.approve(address(vault), 2e18);
    vault.deposit(1e18, ALICE);
    vault.deposit(1e18, BOB);
    assertEq(vault.balanceOf(ALICE), 1e18);
    assertEq(vault.balanceOf(BOB), 1e18);
    vm.stopPrank();

    // 2. Share price is not 1 to 1
    assertEq(vault.previewRedeem(1e18), 1e18);

    SendParam memory sendParam;
    sendParam.to = bytes32(uint256(1));
    sendParam.amountLD = 1e18;

    MessagingFee memory fee;

    // 3. Bob transfers his share to another chain
    vm.prank(BOB);
    vault.send(sendParam, fee, BOB);

    // Since the share is burnt on the source chain, share price has increased
    assertEq(vault.previewRedeem(1e18), 2e18);

    // 4. Alice redeems her share, getting Bobs share as well
    vm.prank(ALICE);
    vault.redeem(1e18,ALICE, ALICE);

    assertEq(vault.balanceOf(ALICE), 0);
    assertEq(asset.balanceOf(ALICE), 2e18);

    Origin memory origin;
    origin.sender = bytes32(uint256(1));
    (bytes memory message,) = OFTMsgCodec.encode(
        bytes32(uint256(uint160(BOB))),
        1e6,
        ""
    );

    // 5. Bob transfers back
    vm.prank(LZ_ENDPOINT);
    vault.lzReceive(
        origin,
        bytes32(uint256(0)),
        message,
        LZ_ENDPOINT,
        ""
    );

    // Bobs share is now worth nothing as Alice has redeemed it
    assertEq(vault.balanceOf(BOB), 1e18);
    assertEq(vault.previewRedeem(1e18), 0);

    vm.prank(BOB);
    vm.expectRevert("ZERO_ASSETS");
    vault.redeem(1e18, BOB, BOB);
}

function _debit(address _from, uint256 _amountLD, uint256 _minAmountLD, uint32 _dstEid) internal virtual override returns (uint256 amountSentLD, uint256 amountReceivedLD) {
    (amountSentLD, amountReceivedLD) = _debitView(_amountLD, _minAmountLD, _dstEid);
    // Instead of burning, transfer to this contract
    _transfer(_from, address(this), amountSentLD);
}

function _credit(address _to, uint256 _amountLD, uint32) internal virtual override returns (uint256 amountReceivedLD) {
    if (_to == address(0x0)) _to = address(0xdead);
    _transfer(address(this),_to, _amountLD);
    return _amountLD;
}