I'm fairly certainly this is due to approvals- that metamask thinks that an error will be thrown because the contract does not have approval to transfer the ERC20- even though the approval tx is currently pending.
My dapp, just like other Dapps, when it needs to get Dai from a user first asks the user to approve the transfer, then there is a second tx where the actual transfer is made. Of course, by the time the second tx has appeared, the approval transaction has not yet confirmed, so metamask thinks it will fail. But, it doesn't, because the approval tx has a lower nonce so will always confirm first.
I don't see other dapps with this problem, any idea what I'm doing wrong? Why can metamask usually take into account a pending tx when trying to figure out if a new tx will fail, but in my case it can't?
See it for yourself, my dapp is public, on kovan. You will need kovan ETH. Please visit harber.io and click on any team. Then press 'Get $100 Test Dai' and wait until confirmed. Then select a rental price and deposit (rental price must be higher than whatever it currently is, deposit must be less than 100) and press 'rent token'. You will see two transactions, the first is the approval for the exact amount of the transfer, and the second is to transfer the Dai. The second transaction, before pressing submit, has the error:
'ALERT: Transaction Error. Exception thrown in contract code.'
But go ahead and submit it, it will work fine.
The front end code which is initiating the two transactions is here.
For reference, here are the two relevant txs on etherscan:
The transferFrom tx (called via my contract): https://kovan.etherscan.io/tx/0xe4e4b79425c9d639dea20e67ca761d4ca34509380a45920f0f593ee806a60aaf
Both confirm just fine with zero errors. Yet for the second tx, metamask reported said the tx would throw.
I found the solution :) it turns out that I'm an idiot.
When I said in the OP "I don't see other dapps with this problem, any idea what I'm doing wrong?"
It turns out that other dapps DO have this problem, so they always wait for the first tx to confirm before doing the second tx. My memory was different, but wrong.