hi @frangio
I'd appreciate your opinion on this as it's pretty tricky.
After some time, I figured the following check wouldn't be good.
function _afterTokenTransfer(address from, address to, uint256 amount) internal override(ERC20VotesUpgradeable, ERC20Upgradeable) {
super._afterTokenTransfer(from, to, amount);
if(from == address(0) && to != address(0) && delegates(to) == address(0)) {
_delegate(to, to);
}
}
The reason is _delegate
would only execute in the minting scenario. What if the following scenario happens.
// 1. minted 10 to addr1 at block 230
// 2. addr1 transfers 5 to addr2
// 3. addr1 creates a proposal which for the voting, uses `getPastVotes(account, proposalCreatedBlockNumber)`
// 4. addr1 can vote, but addr2 can NOT vote even if addr2 calls delegate.
In order to solve this, First I thought to do the following:
if(to != address(0) && delegates(to) == address(0)) {
_delegate(to, to);
}
but the problem here is the above scenario I mentioned would work, but if user manually turned of delegation(called delegate(address(0)
), and someone transfered tokens to him, the code would turn on the delegation again, which is bad(we're breaking his rights in some sense). It seems to me the best case is, by default, I turn on delegation for every user(even in mint case or transfer case), but if the user manually turned it off, it's his choice so we shouldn't turn it on again in another transfer. So I come up with this:
// Will only be true in mint/transfer case and if we never turned delegation for the user before.
if (to != address(0) && numCheckpoints(to) == 0) {
_delegate(to, to);
}
NOTE that doing the same check as above for from
is pointless. because from
at some point in time would be to
and it would already have delegation turned on. and if user turned it off, we shouldn't turn it on again.
Can you think of any implications ?