ERC721 Voting power based on some property

If we do that this would be pretty simple.

First I would disable the opt-out option.
Seems that defaulting to the current account as the delegatee should do the trick

    function delegates(address account) public view virtual override returns (address) {
        address delegatee = _delegation[account];
        return delegatee == address(0) ? account : _delegation[account];
    }

Then, in the ERC721Votes we'd want to send in the adjusted amount instead of 1

   function _afterTokenTransfer(
       address from,
       address to,
       uint256 tokenId
   ) internal virtual override {
       _transferVotingUnits(from, to, powerForToken(tokenId));
       super._afterTokenTransfer(from, to, tokenId);
   }

Then all we need to do is come up with some kind of a calculation for the powerForToken()

    /// Just for kicks
    function powerForToken(uint256 tokenId) public returns (uint256) {
        return tokenId ** (totalSupply-tokenId);
    }

What say you @kiko?
Would that work for your use-case?

[EDIT]

not yet complete though
We'd just need to map _getVotingUnits() to the current total voting power of an account.
I think this should work. Haven't tested this yet :crossed_fingers:

  function _getVotingUnits(address account) internal view virtual override returns (uint256) {
    return getVotes(account)
  }
1 Like

Hi,
Following up on the conversation

Mapping _getVotingUnits() to getVotes() wasn't a good idea. There's a need to use another storage variable to track the (undelegated) voting power of each account. I called it _unitsBalance

The rest seems to have worked out quite alright.
Link to PR #3755

However, I do consider reverting the delegation function if the requested delegetee is the same as the one already assigned (meaningless operation). Row #138

What do you think @frangio ?

Just to be clear I'm not sure if this is something we would include in OpenZeppelin Contracts, we need to discuss it more.

By undelegated do you mean when the token holder is who has the voting power as opposed to another account (the delegate)? At least in the ERC20Votes/ERC721Votes model that follows COMP's delegation model we consider that a "self-delegation", so according to this definition the tokens would never be undelegated. Can that be reused instead of adding a new variable?

1 Like

Let me try to clarify, I think 'undelegated' was the wrong word to use here.
By 'undelegated' I meant the balance of voting power that's under the control of that account. I.e. the equivalent of balanceOf(), but for a voting-power adjusted balance.

"self-delegation" is good when used in the opt-out by default model. Then, the default state of 'non-deleted' saves gas.
In this implementation there's no untracked state so requiring an addition delegation to oneself in order to use one's own voting power would add a redundant call that would end up using more gas.
This contract would be more gas-friendly if it implement the self-delegation by default.

Update:
So, removed the forced opt-in and went back to opt-out using the traditional Votes contract
Keeping the opt-in mechanism takes most of the code out of it and leaves use with just 1 storage variable to keep track of adjusted balance (quantity*quality) for each user and 1 function for returning power for each token.

There seems to be no feasible way to lose that variable. I think this is as small as this can get.