ERC20 Approval event conformance
I found that OZ ERC20 implementation differs with your DAI implementation.
-
OZ ERC20 emits
Approvalevent on every approval change:- [x]
approvehttps://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol#L217 - [x]
transferhttps://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol#L63 - [x]
transferFromhttps://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol#L100 - [x]
_burnFromhttps://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol#L228
- [x]
-
DAI implementation emits
Approvalevent only insideapprovemethod:- [x]
approvehttps://github.com/makerdao/dss/blob/master/src/dai.sol#L100 - [ ]
transferhttps://github.com/makerdao/dss/blob/master/src/dai.sol#L76 - [ ]
transferFromhttps://github.com/makerdao/dss/blob/master/src/dai.sol#L76 - [ ]
burnhttps://github.com/makerdao/dss/blob/master/src/dai.sol#L92
- [x]
ERC20 Token Standard tells:
Approval MUST trigger on any successful call to
approve(address _spender, uint256 _value).
For me it seems OZ implementation should be fixed to conform, or maybe they have some reasons to follow this behavior.
@nventuro provided a link to the discussion where they came up to the decision to emit Approval event on every allowance change: https://github.com/OpenZeppelin/openzeppelin-contracts/issues/707
If you want to reconstruct the allowance fron LOGS (which is not really recommended, as LOGS shouldnt be relied upon for historical data) you can easily recalculate it from the Approval + Tranfer events. I dont think we should add additional logs here.
For the record, permit also emits an Approval event
@MrChico main OZ point was that it is not possible to recover state based on Approval+Transfer events since account can transferFrom to different destination than its own address.
Using logs to recover state is not a good practice. I'm not sure that one would want to condone such behaviour
@MrChico is there any particular reason why you wouldn't rely on logs?
it is not possible to recover state based on Approval+Transfer events since account can transferFrom to different destination than its own address.
Recovering state is not the only issue: when using transferFrom with no Approval events, it is not possible to notice that the allowance has changed from just the event logs: you'd have to look inside the calldata, extract the function selector, and compare it against transfer and transferFrom's.
That sounds like recovering state to me. Determining the allowance of a user is easy, you just fetch the corresponding allowance from state. Maybe you describe a use case where not having the Approval event in these functions would cause an issue?
The two basic use cases for events are: a) create a timeline for state, and b) react to something. transferFrom modifies allowance without emitting an Approval event, so it is not possible to react to allowance changes using events alone.
@nventuro case b makes more sense for me.
For clarity, the thing that is a bad practice is using logs to recover ancient data like many dapps do. What logs are useful for is people who want to monitor/track changes live (which they then may store in an external database for historical lookup). In general, you log basically the same thing regardless of whether the user is just tracking head or trying to lookup ancient state. The thing that is a bad practice is relying on those logs being available forever.
Thanks for everybody's comments. I dont have a strong feeling about this, and it seems like others do. So in the case of this contract one would add another event in the TransferFrom clause that actually diminishes the allowance? That would be L75 in dai.sol
One last feeble attempt at ERC777: I think the right solution here is to have DAI be an ERC777 token instead of ERC20. ERC777 is backward compatible with ERC20, but it fixes a lot of mistakes that were made in ERC20, including this one.
@MicahZoltu sorry, but I can't understand why anyone would prefer ERC777 instead of ERC20. For me, it seems like an overdeveloped solution with the not clear idea behind it. Additionally, operators behave like infinite approves, which are very dangerous. I'd better add to Ethereum ability to group multiple transactions in one to make atomic approve+call: ethereum/EIPs#2243
@k06a ERC-777 operators are not the same as ERC20 approvals, they are intended for "this address is allowed to operate on my tokens on my behalf" rather than "I want to transfer some tokens as part of a larger transaction". For the latter, you would use send(to, amount, calldata) so you can send some tokens and then follow-up with a contract call. For example, if you wanted to send DAI to a maker contract to close out some debt you would do so with send(cdp, amount, <calldata_for_debt_closure>).
Unlike ERC20, ERC777 went through a lot of rounds of feedback between a lot of people who have worked with ERC20 (and other) tokens in the past. Everything in it is incredibly deliberate (unlike ERC20) and serves a distinct purpose. If you think something in ERC777 doesn't make sense, I recommend reading through the discussion history for its development as I can almost guarantee that whatever concern you have was brought up and debated.
Yeah. Not a fan of 777. Calls to unknown code goes strictly against the praxis of this codebase
@MrChico This would be at the edge and for ecosystem interoperability. Already vat.dai doesn't follow any standard, the DAI token contract exists explicitly for ecosystem integration and standardization. Basically everything about the DAI token contract goes against the praxis of this codebase because it is an integration point and it has intentionally been designed to live external to the rest of Maker so that it can go against the norms found throughout the maker codebase without having to put the rest of the Maker codebase at risk.