they're minimal: just what is needed for inter-contract communication inside our own system
avoided interface-to-interface inheritance even though it's possible, because it gets very messy when dealing with functions that return custom structs as we often use
contracts should inherit their interface where possible, so we can enforce that these functions exist and don't end up with mysterious errors in testing due to unimplemented functions
One downside of not using interface-interface inheritance is that we need to use multiple interfaces to interact with a contract sometimes. For example, if we want to do totalSupply on Shares we would actually do IERC20(myShares).totalSupply, which is not the most intuitive.
Thankfully this naturally goes away the more we merge components.
We could also change this behaviour somehow else (e.g. implement functions on the inheriting contracts that just relay the call up the inheritance chain) but that's worse than just using another interface imo.
A few notes on the interfaces:
One downside of not using interface-interface inheritance is that we need to use multiple interfaces to interact with a contract sometimes. For example, if we want to do
totalSupply
on Shares we would actually doIERC20(myShares).totalSupply
, which is not the most intuitive. Thankfully this naturally goes away the more we merge components. We could also change this behaviour somehow else (e.g. implement functions on the inheriting contracts that just relay the call up the inheritance chain) but that's worse than just using another interface imo.