# Self-delegation in ERC20Votes

**URL:** <https://forum.openzeppelin.com/t/self-delegation-in-erc20votes/17501>\
**Category:** Contracts\
**Tags:** erc20\
**Created:** [October 25, 2021, 12:04am UTC](https://forum.openzeppelin.com/t/self-delegation-in-erc20votes/17501 "2021-10-25T00:04:37Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![AlexMarty](https://avatars.discourse-cdn.com/v4/letter/a/8baadc/32.png) [@AlexMarty](https://forum.openzeppelin.com/u/AlexMarty)\
**Post date:** [October 25, 2021, 12:04am UTC](https://forum.openzeppelin.com/t/self-delegation-in-erc20votes/17501/1 "2021-10-25T00:04:37Z")

</div>

Hi!

I'm using the ERC20Votes extension for my ERC20 token and I would like to assign balance = voting power.

If I understood the documentation correctly, in order to have your voting power = token balance, each wallet should self delegate itself.

> By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked. Enabling self-delegation can easily be done by overriding the [`delegates`](https://docs.openzeppelin.com/contracts/4.x/api/token/erc20#ERC20Votes-delegates-address-) function. Keep in mind however that this will significantly increase the base gas cost of transfers. [(source)](https://docs.openzeppelin.com/contracts/4.x/api/token/erc20#ERC20Votes)

Should this happen only once in order to activate checkpoints?

It's still not really clear on how this should work.  
If someone has an example of a Token implementation that has balance=voting power, that would be awesome!

Thanks for your time!

---

<div class="post-metadata">

**Author:** ![Skyge](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/skyge/32/343_2.png) [@Skyge](https://forum.openzeppelin.com/u/Skyge)\
**Post date:** [October 25, 2021, 1:25am UTC](https://forum.openzeppelin.com/t/self-delegation-in-erc20votes/17501/2 "2021-10-25T01:25:50Z")

</div>

Yeah, if you want `voting power = token balance`, you should delegate to yourself.  
And if you only want to delegate to yourself, yes, you just need to do this once.

---

<div class="post-metadata">

**Author:** ![AlexMarty](https://avatars.discourse-cdn.com/v4/letter/a/8baadc/32.png) [@AlexMarty](https://forum.openzeppelin.com/u/AlexMarty)\
**Post date:** [October 25, 2021, 2:21am UTC](https://forum.openzeppelin.com/t/self-delegation-in-erc20votes/17501/3 "2021-10-25T02:21:59Z")

</div>

The token will have multiple holders and lots of transfers.  
I still don't understand if I should self-delegate to each new holder or only once to the owner of the token.

Do you have any example of an implementation of the self-delegate part?

---

<div class="post-metadata">

**Author:** ![TtheBC01](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/tthebc01/32/14174_2.png) [@TtheBC01](https://forum.openzeppelin.com/u/TtheBC01)\
**Post date:** [October 25, 2021, 3:26am UTC](https://forum.openzeppelin.com/t/self-delegation-in-erc20votes/17501/4 "2021-10-25T03:26:37Z")

</div>

When a user receives the ERC20 token that has the ERC20Votes extension (like buying from a CEX or trading for them in a DEX), they simply have to submit a transaction to the token contract to the function `delegate(address delegatee)` (similar concept to calling the `approve` function). The user will put their wallet address in for the `delegatee` argument to self delegate. Then, as long as the user holds their ERC20 tokens, they will retain the votes they delegate to themselves through this delegate transaction.

---

<div class="post-metadata">

**Author:** ![frangio](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/frangio/32/15251_2.png) [@frangio](https://forum.openzeppelin.com/u/frangio)\
**Post date:** [October 27, 2021, 6:30pm UTC](https://forum.openzeppelin.com/t/self-delegation-in-erc20votes/17501/5 "2021-10-27T18:30:08Z")

</div>

If you want to automatically trigger self-delegation for everyone, you could override `_mint` or `_beforeTokenTransfer` to add a call to `_delegate`.

---

<div class="post-metadata">

**Author:** ![novaknole](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/novaknole/32/3796_2.png) [@novaknole](https://forum.openzeppelin.com/u/novaknole)\
**Post date:** [November 1, 2021, 2:43pm UTC](https://forum.openzeppelin.com/t/self-delegation-in-erc20votes/17501/6 "2021-11-01T14:43:04Z")

</div>

I was wondering what is the better use case than token balance to have it as voting power ?

Why wouldn't I want to call `delegate` for each user so that their accounts can be in the checkpoints and then use my `voting` contract to account for this ?

I guess, the only use case I can think of is that if users that don't participate in the voting, they don't need to call `delegate` and that's it, right ? @frangio

---

<div class="post-metadata">

**Author:** ![frangio](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/frangio/32/15251_2.png) [@frangio](https://forum.openzeppelin.com/u/frangio)\
**Post date:** [November 2, 2021, 8:34pm UTC](https://forum.openzeppelin.com/t/self-delegation-in-erc20votes/17501/7 "2021-11-02T20:34:05Z")

</div>

Checkpoints are expensive book-keeping. It wouldn't make sense for a Uniswap Pair contract to track its balance checkpoints, for example, or an arbitrage bot. So delegation is opt-in as an optimization.

---

<div class="post-metadata">

**Author:** ![DeveloperMarwan](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/developermarwan/32/17968_2.png) [@DeveloperMarwan](https://forum.openzeppelin.com/u/DeveloperMarwan)\
**Post date:** [January 14, 2022, 6:50pm UTC](https://forum.openzeppelin.com/t/self-delegation-in-erc20votes/17501/9 "2022-01-14T18:50:00Z")

</div>

Hi @frangio ,

Would not it be the `_afterTokenTransfer` that needs overriding? I would think that when `_beforeTokenTransfer` is executed, the user does not yet have the tokens so how can they delegate the tokens to themselves. Whereas when `_afterTokenTransfer` is executed, the user would have the tokens. Just want to make sure I understand the sequence.

Thanks!

---

<div class="post-metadata">

**Author:** ![frangio](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/frangio/32/15251_2.png) [@frangio](https://forum.openzeppelin.com/u/frangio)\
**Post date:** [January 14, 2022, 7:02pm UTC](https://forum.openzeppelin.com/t/self-delegation-in-erc20votes/17501/10 "2022-01-14T19:02:15Z")

</div>

Good question. It's indifferent, but it may be a bit cheaper to do it in `_afterTokenTransfer`. The reason it's the same is that once an account defines a delegate, all of its balance is delegated including what it is about to receive.

---

<div class="post-metadata">

**Author:** ![DeveloperMarwan](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/developermarwan/32/17968_2.png) [@DeveloperMarwan](https://forum.openzeppelin.com/u/DeveloperMarwan)\
**Post date:** [January 14, 2022, 8:05pm UTC](https://forum.openzeppelin.com/t/self-delegation-in-erc20votes/17501/11 "2022-01-14T20:05:27Z")

</div>

Thanks for the reply and explanation @frangio . Much appreciated.

---

<div class="post-metadata">

**Author:** ![novaknole](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/novaknole/32/3796_2.png) [@novaknole](https://forum.openzeppelin.com/u/novaknole)\
**Post date:** [January 23, 2022, 1:19pm UTC](https://forum.openzeppelin.com/t/self-delegation-in-erc20votes/17501/12 "2022-01-23T13:19:44Z")

</div>

Hi @frangio,

You mention to override `afterTokenTransfer` or `_mint` and include `_delegate` there. Let's say in every mint, I included `_delegate` as well. In such case, if user mints 2nd time, `_delegate` will still be called for no reason. Isn't it like a bad thing?

The comments in the doc states to override `{delegates}` function.

What if I do the override for this:

```auto
function delegates(address account) public view virtual returns (address) {
        return _delegates[account];
    }

```

and instead of this, I got

```auto
function delegates(address account) public view virtual returns (address) {
        return account;
    }

```

What downside will it have ? it seems to work.

---

<div class="post-metadata">

**Author:** ![frangio](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/frangio/32/15251_2.png) [@frangio](https://forum.openzeppelin.com/u/frangio)\
**Post date:** [January 24, 2022, 10:18pm UTC](https://forum.openzeppelin.com/t/self-delegation-in-erc20votes/17501/13 "2022-01-24T22:18:50Z")

</div>

> [@novaknole](#):
>
> The comments in the doc states to override `{delegates}` function.

Sorry, this was an inaccurate comment that we [removed a few weeks ago](https://github.com/OpenZeppelin/openzeppelin-contracts/commit/a0a8bbb57f6a28ae5efb77b1ad06eab65aa93d0d) but the site wasn't updated yet.

Overriding `delegates` will not work correctly. For example, an account will still be able to change their delegate to another account but `delegates` will continue to return the same account and this will lead to inconsistencies.

The correct solution as far as I can tell is to use the transfer hooks. The implementation that I described above is perhaps too simplistic. We'd have to refine what behavior exactly we want. For example perhaps only for mints where the receiving account doesn't have a delegate already.

---

<div class="post-metadata">

**Author:** ![novaknole](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/novaknole/32/3796_2.png) [@novaknole](https://forum.openzeppelin.com/u/novaknole)\
**Post date:** [February 1, 2022, 2:59pm UTC](https://forum.openzeppelin.com/t/self-delegation-in-erc20votes/17501/14 "2022-02-01T14:59:03Z")

</div>

Hi @frangio Thanks for the comments.

Maybe you can give it a look and see if my solution is now good.

I included explanation in comments below. WDYT ?

```auto
contract GovernanceWrappedERC20 is ERC20VotesUpgradeable, ERC20WrapperUpgradeable {
   // The functions below are overrides required by Solidity.
    function _afterTokenTransfer(address from, address to, uint256 amount) internal override(ERC20VotesUpgradeable, ERC20Upgradeable) {
        super._afterTokenTransfer(from, to, amount);
        // This means that minting happens. and this will only be called 
        // at those times that minting happens only. For transfers, it doesn't
        // make sense to be calling `_delegate` again and again, since more gas
        // costs for no reason. Though, I don't like the below as well, because
       // if user mints 5 times, calling _delegate 5 times is not good. All. 
      // I am saying is calling _delegate should only be needed only once 
      // and once in lifetime.First of all, is below correct and if there's a better way 
      // such as calling `_delegate` multiple times is not needed.
        if(from == address(0) && to != address(0)) {
            _delegate(to, to);
        }
    }

}

```

Thank you.

---

<div class="post-metadata">

**Author:** ![frangio](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/frangio/32/15251_2.png) [@frangio](https://forum.openzeppelin.com/u/frangio)\
**Post date:** [February 1, 2022, 8:37pm UTC](https://forum.openzeppelin.com/t/self-delegation-in-erc20votes/17501/15 "2022-02-01T20:37:32Z")

</div>

This looks ok, but has the downside that if an account has already customized their delegate, a mint would overwrite it. So you can do something like:

```auto
    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);
        }
    }

```

---

<div class="post-metadata">

**Author:** ![novaknole](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/novaknole/32/3796_2.png) [@novaknole](https://forum.openzeppelin.com/u/novaknole)\
**Post date:** [February 21, 2023, 9:25pm UTC](https://forum.openzeppelin.com/t/self-delegation-in-erc20votes/17501/16 "2023-02-21T21:25:41Z")

</div>

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.

```auto
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.

```auto
// 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:

```auto
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:

```auto
// 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 ?

---

<div class="post-metadata">

**Author:** ![frangio](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/frangio/32/15251_2.png) [@frangio](https://forum.openzeppelin.com/u/frangio)\
**Post date:** [February 22, 2023, 10:23pm UTC](https://forum.openzeppelin.com/t/self-delegation-in-erc20votes/17501/17 "2023-02-22T22:23:28Z")

</div>

There are still edge cases in your example. If the account delegates prior to having received tokens you don't want to overwrite their delegate, and they will not have any checkpoints if they've delegated to someone else.

I think your best bet is to add a new variable to store whether the user has manually opted in to any form of delegation (`mapping (address => bool)`), and only if they haven't you set the default delegate for them.

---

<div class="post-metadata">

**Author:** ![novaknole](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/novaknole/32/3796_2.png) [@novaknole](https://forum.openzeppelin.com/u/novaknole)\
**Post date:** [February 24, 2023, 6:45am UTC](https://forum.openzeppelin.com/t/self-delegation-in-erc20votes/17501/18 "2023-02-24T06:45:36Z")

</div>

@frangio

Aren't there really anything in `ERC20Votes` that could solve this ?

So, you suggest that I override `delegate` function in which I do:

```auto
userDelegations[account] = true;
super._delegate(...);

```

I'm trying to not bring new state as for the first time, the gas cost of transfer would increase by 22k.

I think this should finally work:

```auto
if (to != address(0) && numCheckpoints(to) == 0 && delegates(to) == address(0)) {
    _delegate(to, to);
 }

```

Thought ?

---

<div class="post-metadata">

**Author:** ![frangio](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/frangio/32/15251_2.png) [@frangio](https://forum.openzeppelin.com/u/frangio)\
**Post date:** [February 24, 2023, 3:31pm UTC](https://forum.openzeppelin.com/t/self-delegation-in-erc20votes/17501/19 "2023-02-24T15:31:10Z")

</div>

I think that solution is good enough!
