Setting a v2 offer owner with address(0) will trick `RubiconMarket.buy()` to think it's dealing with a v1 offer and it will silently lose funds instead of reverting.
Audit: 2023-04-rubicon-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-04-rubicon/blob/main/contracts/RubiconMarket.sol#L349-L363
https://github.com/code-423n4/2023-04-rubicon/blob/main/contracts/RubiconMarket.sol#L533


# Vulnerability details

`RubiconMarket.sol` will check for `owner == address(0)` in some instances to test is it's v1->v2 migration, however since it's possible to set `offer.owner` with address(0) in `RubiconMarket.offer()`, unexpected failures may occur because the contract will think it's dealing with a v1 offer, but instead it will be dealing with an invalid v2 offer, which can cause loss of funds.

## Impact

Transferring to the zero address is not an issue for most erc20 token, because the standard implementations (e.g. OpenZeppelin) revert when the receiver is address(0). 

However, the tricky aspect here is, since the protocol expects `offer.owner` to be address(0) for v1 offers, it would silently lose the funds in case `offer.owner` gets initialized with address(0) for v2. In practice, setting address(0) on `RubiconMarket.offer()` and `SimpleMarket.offer()` would likely be a user mistake and it should revert instead of causing loss of funds.

## Proof of Concept

The following POC can be added into `ProtocolDeployment.ts` to check that setting the address(0) for `offer.owner` on [SimpleMarket.offer()](https://github.com/code-423n4/2023-04-rubicon/blob/main/contracts/RubiconMarket.sol#L533) will not revert and then calling [SimpleMarket.buy()](https://github.com/code-423n4/2023-04-rubicon/blob/main/contracts/RubiconMarket.sol#L349-L363) will also not revert. We can also check that the maker won't receive the fees.

```javascript
it("POC: setting owner as address zero silently breaks `buy()` for v2 offers", async () => {
  const { rubiconMarket, testStableCoin, testCoin, owner, testMaker } =
    await loadFixture(deployRubiconProtocolFixture);

  // set MakerFee
  await rubiconMarket.setMakerFee(10);
  const quantity = parseUnits("5", 6);
  const received = parseUnits("6");

  await testStableCoin
    .connect(testMaker)
    .approve(rubiconMarket.address, quantity);

  // pass addr(0) as owner
  await rubiconMarket
    .connect(testMaker)
    .functions["offer(uint256,address,uint256,address,address,address)"](
      quantity,
      testStableCoin.address,
      received,
      testCoin.address,
      ethers.constants.AddressZero, // offer.owner
      owner.address // offer.recipient
    );

  const receivedAfterFee = await rubiconMarket.calcAmountAfterFee(
    received
  );
  const feeAmount = receivedAfterFee
    .sub(await rubiconMarket.calcAmountAfterFee(receivedAfterFee))
    .div(2);
  const makerBalanceBefore = await testCoin.balanceOf(testMaker.address);

  await rubiconMarket.buy(5, quantity);

  const makerBalanceAfter = await testCoin.balanceOf(testMaker.address);

  // expected assertation will fail
  // expect(makerBalanceAfter.sub(makerBalanceBefore)).to.be.equal(
  //   feeAmount
  // );

  // maker's balance after `buy()` w