openzeppelin-contracts icon indicating copy to clipboard operation
openzeppelin-contracts copied to clipboard

claimandDelegate function for compound-style delegation upon token claim

Open owocki opened this issue 3 years ago • 4 comments

🧐 Motivation

GTC is a UNI fork.

During the GTC drop, we enabled people to delegate upon claim which was a really effective way of setting the initial distribution of governance to have high consent of the governed.

Upon conversation at Martin at ETHDenver, we realized that since the ENS drop did the same thing, this is a common functionality that future drops may want to use, and that therefore it would be a good idea to have a claimandDelegate() function in an upstream OpenZeppelin repo, so that people have this in the future.

📝 Details

I believe that this would be what would have to happen in the repo.

  1. Write a claimandDelegate() function into the repo.
  2. Done

owocki avatar Mar 01 '22 16:03 owocki

Hello @owocki

I did hear about this "delegate upon claim" mechanism from the ENS team. This was indeed implemented in their token.

AFAIK, we provide the primitives for it

  • _delegate(address, address);
  • _mint(address, uint256);
  • _transfer(address, address, uint256);

In order to go further, we would be defining a "claim" process, with a "standard" merkle tree format. IMO this is something that each team may want to customize, and we should "just" provide the tools for making that easy, without actually imposing a "strict" framework. I would argue that we are providing these tools. Maybe we are missing some, but I'm not sure what we are missing it a "ready to use" claim function.

@frangio What do you think? Should we provide a ERC20MerkleDrop extension, that includes a _delegate call during the claim call ?

Amxx avatar Mar 01 '22 16:03 Amxx

I just noticed that unlike ENS, your code uses a TokenDistributor that is NOT the token itself.

For these cases, you can either use a signed delegation message by the user ... or have the token expose a permissioned access to _delegate that only the distributor can call (I think this is not as nice in terms of security)

Amxx avatar Mar 01 '22 16:03 Amxx

Thanks for the suggestion @owocki! I thought the ENS distribution was really clever in how it guided users to set a delegate during claiming. I didn't know GTC had done the same thing previously.

As a side note, in my experience a big part of the ENS claim experience was the UI, which is not something OpenZeppelin Contracts can directly help with, but OpenZeppelin Subgraphs definitely may be able to provide the building blocks. @Amxx Is there a way to query "delegates" sorted by delegated voting power?

Regarding the contracts, I agree with @Amxx that we don't want to implement a very specific claim process that may not apply well to diverse user needs. But if there is a straightforward way to implement a claim process like this, and it looks like there is demand for this sort of contract, I think we should look into implementing it.

we should "just" provide the tools for making that easy

The question is if the tools we provide now make it easy enough. MerkleProof is very general, and there may be room for a more ready-made solution.

I find the ENS model of building the claim function into the token itself nice and simple. Interestingly it doesn't use _mint but _transfer of a number of tokens minted at deployment (which are even sweeped away later). I wonder if this is a measure to limit the impact of a potential problem with the claim code. Separating the claiming concern in its own contract may be considered better design. Personally I'm not decided.

frangio avatar Mar 08 '22 04:03 frangio

I don't have a live example to show, but using @openzeppelin/subgraph's "voting" module, the following query is possible

VotingContract(id: "<address-of-the-contract-in-lowercase>") {
    delegation(first: 100, orderBy: "value", orderDirection: "desc") { // 100 biggest delegates
        value // ← number of "votes" (wei)
        account {
            id // ← address of the delegate
            delegationTo { // ← loop over all delegation to this delegate
                delegator {
                  id // ← address of the delegator
                }
            }
        }
    }
}

Amxx avatar Mar 08 '22 08:03 Amxx