I got several out of gas errors attempting to purchase a fractional listing. I incremented the gas manually in metamask and eventually got it to work (it did take about 5 attempts though).
Additionally, once a purchase fails you can't attempt to purchase again as it immediately errors with a "See console" error and diplays "Expected event not found" in the console. This is probably because GraphQL gets confused by the failure.

From a contract perspective, what is different with fractional listings ?
Looking at the contract code, I don't see any difference in the code executed for making an offer on a fractional vs traditional listing... So why would it require more gas ?
CC @nick and @shahthepro since they have more background on fractional.
Fractional might not be relevant here, it might be just listings in general.
Yea no difference between fractional and non-fractional at the contract level. We probably just need to bump the amount of gas up a bit here. Which value worked for you, Tom?
Tried a few times with the default of 301785, bumped it to 401785 and still failed, then succeeded with 1001785. Probably not the most efficient. 😁
@tomlinton Was this on staging? No relayer, I'm assuming? Was this using proxy contracts?
It was mainnet, pretty fresh identity deployed with a proxy. Relayer doesn't get used for make offer calls afaik? You have to pay gas for ETH transfer anyway.
@tomlinton Can you get me a eth TXN hash for that purchase? Or discord message me your ETH address.
Looking back at the transactions now, it involves a DAI swap so the relayer would have been involved. The swap might be the cause here.
Failures:
0xa4cf4abfe23822632ea9d2524e2aedc11bd6685da1ad811fcb2282c0afc3bfa9
0x7620ff1942ec08d766034bbd0d701396e09eebb4300f17d0157bea9422ccf701
0xd5f123487fc070a5d3737fb0ee29c7612747dfee1310fbaec65ad53a2d960f00
0xe774fc9e5e74dcfebe8b321d56d265a9358518425e62ab5bf2b470d5e5e3025c
Success:
0x9d42f0e055f8e5830dcc45cd4c51ad39358cf33b9bc7b3ae787661c0883d6534
I'm fairly certain this is the DIA swap that is costing a bit extra.
I'm pulling the data to be able to know exactly what this cost really is, and how variable it is.
Turns out there may be a simple answer.
But stories with red herrings and wrong trails are more fun to read.
First I yanked down a set of 3,000 consecutive transactions from the DIA uniswap contract, and split them up by contract method to see what was being called, and how much they cost.

Then I broke that down to just the ones that accepted ether:

And finally just the function that we call:

Two interesting things here:
No real answer here though.
Then I had a look at the @tomlinton's original transactions. The super interesting thing I see is that @tomlinton tried gas amounts of 301k, 301k, 301k, 401k, and 1001k, and yet the final succeeding transaction used only 296K. That should have fit into the gas amount of the first transaction. The problem then must be outside the gas amounts.
The uniswap exchange contract ethToTokenSwapOutput function works by taking ETH that you send, and a desired amount of tokens to buy. At the transaction time, the contract calculates the current price and number of tokens your eth can buy.
https://github.com/Uniswap/contracts-vyper/blob/master/contracts/uniswap_exchange.vy#L173-L174
Because of the way the uniswap exchange works, I think the exchange rate changes after each transaction.
When we calculate how much eth to send for DIA:
const value = await exchange.methods
.getEthToTokenOutputPrice(tokenValue)
.call()
const tx = exchange.methods.ethToTokenSwapOutput(tokenValue, deadline)
return { tx, value }
We get the current exchange rate, but if any other exchange transaction happens between us getting the rate, and the transaction being mined, and it causes the rate to change in the wrong direction, it would cause our transaction to fail.
It's possible we may need to send a little extra ETH and expect a refund, or have a retry mechanism (boo).
I'll pull our relayer history and see if, and how often, this is happening, and if this is the real problem.
Short summary:
I'm now 100% sure that this is an issue. I cloned the Uniswap exchange vyper contracts, and modified the tests to check that it does indeed throw the transaction if you send event trillionth less eth than is required.
How often does this happen?

I also download the last 48 days of logs from the uniswap ETH-DIA contract. It's an fairly active contract. It averages a transaction every 10.4 blocks, or about 23.6 transactions an hour.

The buying and selling transactions were roughly evenly split. I'll just call it 50/50

Here's a histogram of the difference in prices between previous buy transactions:

It leans to one side, but I think that's because the market as a whole certainly made strong moves in a certain direction during this.
To know what we need to do to be safe. I absoluted the changes, then sorted them.

So in theory, adding 1% extra eth would handle 98% of price changes.
That's measured in prices changes though, not a percentage of our transactions. Our actual odds are better than that, since not every block contains a price change. But to actually calculate what percentage of our DIA purchases that would effect, we need to know how long it takes from when a user clicks "purchase", and signs the transaction, to that transaction being mined.
I don't have that data. If we assume 3 blocks as a best case, than our current code would work about 85% of the time. If that's 6 blocks, then success about 71% of the time.
After a 1% increase in ETH sent, then that goes to 99.5% success at 3 and 98.8% at 6.
Our makeOffer transaction gas prices goes up by 20,000 gas per transaction (roughly a 6% increase).
However, then we will be getting a refund for every successful DAI buy. When using a proxy, this refund will go to the proxy. We'd need to modify our swapAndMakeOffer method on the identity proxy to send any refund back to the owner. This second money move will also cost us gas.
I wish I could label comments as "Epic". 🏆 Great work @DanielVF. Thanks for digging into this!
Considering this done unless someone says otherwise ✅
Most helpful comment
Short summary:
Yes, Uniswap works that way.
I'm now 100% sure that this is an issue. I cloned the Uniswap exchange vyper contracts, and modified the tests to check that it does indeed throw the transaction if you send event trillionth less eth than is required.
How often does this happen?
I also download the last 48 days of logs from the uniswap ETH-DIA contract. It's an fairly active contract. It averages a transaction every 10.4 blocks, or about 23.6 transactions an hour.
The buying and selling transactions were roughly evenly split. I'll just call it 50/50
Eth-DIA price chart, for fun.
What percentage do we need to add to be safe
Here's a histogram of the difference in prices between previous buy transactions:
It leans to one side, but I think that's because the market as a whole certainly made strong moves in a certain direction during this.
To know what we need to do to be safe. I absoluted the changes, then sorted them.
So in theory, adding 1% extra eth would handle 98% of price changes.
That's measured in prices changes though, not a percentage of our transactions. Our actual odds are better than that, since not every block contains a price change. But to actually calculate what percentage of our DIA purchases that would effect, we need to know how long it takes from when a user clicks "purchase", and signs the transaction, to that transaction being mined.
I don't have that data. If we assume 3 blocks as a best case, than our current code would work about 85% of the time. If that's 6 blocks, then success about 71% of the time.
After a 1% increase in ETH sent, then that goes to 99.5% success at 3 and 98.8% at 6.
Unfortunately
Our makeOffer transaction gas prices goes up by 20,000 gas per transaction (roughly a 6% increase).
However, then we will be getting a refund for every successful DAI buy. When using a proxy, this refund will go to the proxy. We'd need to modify our swapAndMakeOffer method on the identity proxy to send any refund back to the owner. This second money move will also cost us gas.